Using RxJava 2 to tint & merge an arbitrary number of Bitmaps into a single Bitmap and display the merged bitmap into an ImageView
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class RxjavaBitmapMergeView { | |
SchedulersFacade schedulersFacade; | |
@BindView(R.id.map) | |
ImageView map; | |
@BindArray(R.array.impact_map_colors) | |
@ColorInt | |
int[] mapColors; | |
@BindBitmap(R.drawable.map_layer_base) | |
Bitmap mapBase; | |
Paint[] mapPaints; | |
CompositeDisposable disposables; | |
public RxjavaBitmapMergeView(@NonNull Context context) { | |
super(context); | |
initialize(); | |
} | |
public RxjavaBitmapMergeView(@NonNull Context context, @Nullable AttributeSet attrs) { | |
super(context, attrs); | |
initialize(); | |
} | |
public RxjavaBitmapMergeView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { | |
super(context, attrs, defStyleAttr); | |
initialize(); | |
} | |
private void initialize() { | |
ActivityComponent activityComponent = ((BaseActivity)getContext()).getActivityComponent(); | |
schedulersFacade = activityComponent.schedulersFacade(); | |
disposables = new CompositeDisposable(); | |
inflate(getContext(), R.layout.view_rxjava_bitmap_merge, this); | |
ButterKnife.bind(this); | |
//Create the Paint objects for all the colors | |
mapPaints = new Paint[mapColors.length]; | |
for(int i = 0; i < mapColors.length; i++) { | |
Paint mapPaint = new Paint(); | |
mapPaint.setColorFilter(new PorterDuffColorFilter(mapColors[i], PorterDuff.Mode.SRC_IN)); | |
mapPaints[i] = mapPaint; | |
} | |
//Tint the mapBase bitmap and set it to the view to start | |
mapBase = tintBitmap(mapBase, mapPaints[0]); | |
map.setImageBitmap(mapBase); | |
} | |
public void setData(@NonNull List<State> usStates) { | |
disposables.add(Observable.fromIterable(usStates) | |
.map(this::getMapBitmapForState) | |
.reduce((merged, next) -> { | |
Canvas canvas = new Canvas(merged); | |
canvas.drawBitmap(next, 0, 0, null); | |
return merged; | |
}) | |
.map(statesBitmap -> { | |
Bitmap mergedMap = mapBase.copy(Bitmap.Config.ARGB_8888, true); | |
Canvas canvas = new Canvas(mergedMap); | |
canvas.drawBitmap(statesBitmap, 0, 0, null); | |
return mergedMap; | |
}) | |
.subscribeOn(schedulersFacade.computation()) | |
.observeOn(schedulersFacade.ui()) | |
.subscribe( | |
mapBitmap -> { | |
BitmapDrawable mapDrawable = new BitmapDrawable(getResources(), mapBitmap); | |
Drawable imageViewDrawable = map.getDrawable(); | |
Drawable[] layers = new Drawable[] {imageViewDrawable, mapDrawable}; | |
TransitionDrawable td = new TransitionDrawable(layers); | |
map.setImageDrawable(td); | |
td.startTransition(1000); | |
}, | |
error -> Timber.e(error, "Error setting map data"), | |
() -> Timber.w("We completed without emitting map data..how did this happen? Not setting map data") | |
)); | |
} | |
private Bitmap tintBitmap(@NonNull Bitmap source, Paint paint) { | |
Bitmap result = Bitmap.createBitmap(getResources().getDisplayMetrics(), | |
source.getWidth(), | |
source.getHeight(), | |
Bitmap.Config.ARGB_8888, | |
true); | |
Canvas canvas = new Canvas(result); | |
canvas.drawBitmap(source, 0, 0, paint); | |
return result; | |
} | |
private Bitmap getMapBitmapForState(State state) { | |
@DrawableRes int stateResId; | |
switch (state.abbreviation().toUpperCase(Locale.getDefault())) { | |
case "AK": | |
stateResId = R.drawable.map_layer_ak; | |
break; | |
case "AL": | |
stateResId = R.drawable.map_layer_al; | |
break; | |
case "AR": | |
stateResId = R.drawable.map_layer_ar; | |
break; | |
case "AZ": | |
stateResId = R.drawable.map_layer_az; | |
break; | |
case "CA": | |
stateResId = R.drawable.map_layer_ca; | |
break; | |
case "CO": | |
stateResId = R.drawable.map_layer_co; | |
break; | |
case "CT": | |
stateResId = R.drawable.map_layer_ct; | |
break; | |
case "DE": | |
stateResId = R.drawable.map_layer_de; | |
break; | |
case "FL": | |
stateResId = R.drawable.map_layer_fl; | |
break; | |
case "GA": | |
stateResId = R.drawable.map_layer_ga; | |
break; | |
case "HI": | |
stateResId = R.drawable.map_layer_hi; | |
break; | |
case "IA": | |
stateResId = R.drawable.map_layer_ia; | |
break; | |
case "ID": | |
stateResId = R.drawable.map_layer_id; | |
break; | |
case "IL": | |
stateResId = R.drawable.map_layer_il; | |
break; | |
case "IN": | |
stateResId = R.drawable.map_layer_in; | |
break; | |
case "KS": | |
stateResId = R.drawable.map_layer_ks; | |
break; | |
case "KY": | |
stateResId = R.drawable.map_layer_ky; | |
break; | |
case "LA": | |
stateResId = R.drawable.map_layer_la; | |
break; | |
case "MA": | |
stateResId = R.drawable.map_layer_ma; | |
break; | |
case "MD": | |
stateResId = R.drawable.map_layer_md; | |
break; | |
case "ME": | |
stateResId = R.drawable.map_layer_me; | |
break; | |
case "MI": | |
stateResId = R.drawable.map_layer_mi; | |
break; | |
case "MN": | |
stateResId = R.drawable.map_layer_mn; | |
break; | |
case "MO": | |
stateResId = R.drawable.map_layer_mo; | |
break; | |
case "MS": | |
stateResId = R.drawable.map_layer_ms; | |
break; | |
case "MT": | |
stateResId = R.drawable.map_layer_mt; | |
break; | |
case "NC": | |
stateResId = R.drawable.map_layer_nc; | |
break; | |
case "ND": | |
stateResId = R.drawable.map_layer_nd; | |
break; | |
case "NE": | |
stateResId = R.drawable.map_layer_ne; | |
break; | |
case "NH": | |
stateResId = R.drawable.map_layer_nh; | |
break; | |
case "NJ": | |
stateResId = R.drawable.map_layer_nj; | |
break; | |
case "NM": | |
stateResId = R.drawable.map_layer_nm; | |
break; | |
case "NV": | |
stateResId = R.drawable.map_layer_nv; | |
break; | |
case "NY": | |
stateResId = R.drawable.map_layer_ny; | |
break; | |
case "OH": | |
stateResId = R.drawable.map_layer_oh; | |
break; | |
case "OK": | |
stateResId = R.drawable.map_layer_ok; | |
break; | |
case "OR": | |
stateResId = R.drawable.map_layer_or; | |
break; | |
case "PA": | |
stateResId = R.drawable.map_layer_pa; | |
break; | |
case "RI": | |
stateResId = R.drawable.map_layer_ri; | |
break; | |
case "SC": | |
stateResId = R.drawable.map_layer_sc; | |
break; | |
case "SD": | |
stateResId = R.drawable.map_layer_sd; | |
break; | |
case "TN": | |
stateResId = R.drawable.map_layer_tn; | |
break; | |
case "TX": | |
stateResId = R.drawable.map_layer_tx; | |
break; | |
case "UT": | |
stateResId = R.drawable.map_layer_ut; | |
break; | |
case "VA": | |
stateResId = R.drawable.map_layer_va; | |
break; | |
case "VT": | |
stateResId = R.drawable.map_layer_vt; | |
break; | |
case "WA": | |
stateResId = R.drawable.map_layer_wa; | |
break; | |
case "WI": | |
stateResId = R.drawable.map_layer_wi; | |
break; | |
case "WV": | |
stateResId = R.drawable.map_layer_wv; | |
break; | |
case "WY": | |
stateResId = R.drawable.map_layer_wy; | |
break; | |
default: | |
throw new IllegalArgumentException(String.format("Unknown state[%s]", state)); | |
} | |
return tintBitmap(BitmapFactory.decodeResource(getResources(), stateResId), | |
mapPaints[state.colorIndex()]); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment