簡單描述使用細(xì)節(jié)場景,根據(jù)界面顏色值動態(tài)切換shape的背景色
這里想到了tint 但因為是動態(tài)修改,在xml中使用更方便
查看tint的源碼:
@Override
public void setTintList(ColorStateList tint) {
final BitmapState state = mBitmapState;
if (state.mTint != tint) {
state.mTint = tint;
mTintFilter = updateTintFilter(mTintFilter, tint, mBitmapState.mTintMode);
// 繪制 最終渲染改變顏色
invalidateSelf();
}
}
Drawable 的子類重寫android.graphics.drawable.Drawable#setTintList 方法 調(diào)用:updateTintFilter
/**
* Ensures the tint filter is consistent with the current tint color and
* mode.
*/
@Nullable PorterDuffColorFilter updateTintFilter(@Nullable PorterDuffColorFilter tintFilter,
@Nullable ColorStateList tint, @Nullable PorterDuff.Mode tintMode) {
if (tint == null || tintMode == null) {
return null;
}
final int color = tint.getColorForState(getState(), Color.TRANSPARENT);
if (tintFilter == null) {
return new PorterDuffColorFilter(color, tintMode);
}
// 注意這里PorterDuffColorFilter 的 setColor 和 setMode 和 后面要提到的setColorFilter 一個意思【也即兼容替換方案】
tintFilter.setColor(color);
tintFilter.setMode(tintMode);
return tintFilter;
}
or v4包下的
private boolean updateTint(int[] state) {
if (this.mTintList != null && this.mTintMode != null) {
int color = this.mTintList.getColorForState(state, this.mTintList.getDefaultColor());
Mode mode = this.mTintMode;
if (!this.mColorFilterSet || color != this.mCurrentColor || mode != this.mCurrentMode) {
//關(guān)注 這里的 setColorFilter
this.setColorFilter(color, mode);
this.mCurrentColor = color;
this.mCurrentMode = mode;
this.mColorFilterSet = true;
return true;
}
} else {
this.mColorFilterSet = false;
this.clearColorFilter();
}
return false;
}
**PorterDuffColorFilter 是ColorFilter的子類
從上面的源碼可以得出最終都通過了ColorFilter完成了color的改變,不管是xml還是動態(tài)代碼都是基于這個,所以可以直接使用 如下:
//but 需要care 兼容性 target 21
@TargetApi(21)
private void tintColor() {
Drawable drawable = getResources().getDrawable(R.drawable.selector_btn_bg);
int color = getResources().getColor(R.color.colorAccent);
drawable.setTint(color);
}
如果非要使用tint 來改變color,可通過兼容性方案setColorFilter 或者如下:
通過v4包下的DrawableCompat類完成兼容tint能力【源碼即前面已經(jīng)提到的源碼中的 or 部分】
Drawable wrapDrawable = DrawableCompat.wrap(drawable);
wrapDrawable.setTint(color);
綜上總結(jié):整個tint基于setColorFilter實現(xiàn),v4包實現(xiàn)兼容
附加不同shape類型 dye時 的代碼:
private void drawableColor() {
try {
int color = getResources().getColor(R.color.colorAccent);
//如果是單層shape 則對應(yīng) GradientDrawable
Drawable background = loanBtn.getBackground();
if (background instanceof GradientDrawable) {
GradientDrawable gd = (GradientDrawable) background;
gd.setColor(color);
// 如果是多層疊加的 shape 則對應(yīng) StateListDrawable
} else if(background instanceof StateListDrawable) {
StateListDrawable sd = (StateListDrawable) background;
sd.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
}
} catch (Exception e) {
e.printStackTrace();
}
}
最后提下setColorFilter 如何渲染的(同 tint 里基本一致,間接證明兩者的相關(guān)性)
@Override
public void setColorFilter(ColorFilter colorFilter) {
mBitmapState.mPaint.setColorFilter(colorFilter);
/** 繪制 v4版本的tint源碼里最后也是如此,
但非兼容版本中是單獨設(shè)置color 和mode 并不會觸發(fā)invalidate,
而是在執(zhí)行完updateStateList后執(zhí)行??這句代碼
*/
invalidateSelf();
}