淺談 Android L 的 Tint(著色)

FredaRule 8年前發布 | 55K 次閱讀 安卓開發 Android開發 移動開發

來自: http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0128/3923.html

淺談 Android L 的 Tint(著色)

Tint 是什么?

Tint 翻譯為著色。

著色,著什么色呢,和背景有關?當然是著背景的色。當我們開發 App 的時候,如果使用了 Theme.AppCompat 主題的時候,會發現 ActionBar 或者 Toolbar 及相應的控件的顏色會相應的變成我們在 Theme 中設置的 colorPrimary, colorPrimaryDark, colorAccent 這些顏色,這是為什么呢,這就全是 Tint 的功勞了!

這樣做有什么好處呢?好處就是你不必再老老實實的打開 PS 再制作一張新的資源圖。而且大家都知道 apk 包最大的就是圖片資源了,這樣減少不必要資源圖,可以極大的減少了我們的 apk 包的大小。

實現的方式就是用一個顏色為我們的背景圖片設置 Tint(著色)。

例子:

大家可以看上面再張圖,這個是做的一個應用“小白球”,如圖 1 的小圖片本來都是白色的(圓背景的單獨設的),但是經過 Tint 著色后就變成了圖 2 中的淺藍色了。

好了,既然理解了tint的含義,我們趕緊看下這一切是如何實現的吧。

其實底層特別簡單,了解過渲染的同學應該知道PorterDuffColorFilter這個東西,我們使用SRC_IN的方式,對這個Drawable進行顏色方面的渲染,就是在這個Drawable中有像素點的地方,再用我們的過濾器著色一次。

實際上如果要我們自己實現,只用獲取View的backgroundDrawable之后,設置下colorFilter即可。

看下最核心的代碼就這么幾行

if (filter == null) {

// Cache miss, so create a color filter and add it to the cache

filter = new PorterDuffColorFilter(color, mode);

}

d.setColorFilter(filter);

通常情況下,我們的mode一般都是SRC_IN,如果想了解這個屬性相關的資料,這里是傳送門: http://blog.csdn.net/t12x3456/article/details/10432935 (中文)

由于API Level 21以前不支持background tint在xml中設置,于是提供了ViewCompat.setBackgroundTintList方法和ViewCompat.setBackgroundTintMode用來手動更改需要著色的顏色,但要求相關的View繼承TintableBackgroundView接

源碼解析

以 EditText 為例,其它的基本一致

public AppCompatEditText(Context context, AttributeSet attrs, int defStyleAttr) {
    super(TintContextWrapper.wrap(context), attrs, defStyleAttr);

...

ColorStateList tint = a.getTintManager().getTintList(a.getResourceId(0, -1)); //根據背景的resource id獲取內置的著色顏色。
if (tint != null) {
    setInternalBackgroundTint(tint); //設置著色
}

...

}

private void setInternalBackgroundTint(ColorStateList tint) { if (tint != null) { if (mInternalBackgroundTint == null) { mInternalBackgroundTint = new TintInfo(); } mInternalBackgroundTint.mTintList = tint; mInternalBackgroundTint.mHasTintList = true; } else { mInternalBackgroundTint = null; } //上面的代碼是記錄tint相關的信息。 applySupportBackgroundTint(); //對背景應用tint }

private void applySupportBackgroundTint() { if (getBackground() != null) { if (mBackgroundTint != null) { TintManager.tintViewBackground(this, mBackgroundTint); } else if (mInternalBackgroundTint != null) { TintManager.tintViewBackground(this, mInternalBackgroundTint); //最重要的,對tint進行應用 } } }</pre>

然后我們進入tintViewBackground看下TintManager里面的源碼

 public static void tintViewBackground(View view, TintInfo tint) {
    final Drawable background = view.getBackground();
    if (tint.mHasTintList) {
        //如果設置了tint的話,對背景設置PorterDuffColorFilter
        setPorterDuffColorFilter(
                background,
                tint.mTintList.getColorForState(view.getDrawableState(),
                        tint.mTintList.getDefaultColor()),
                tint.mHasTintMode ? tint.mTintMode : null);
    } else {
        background.clearColorFilter();
    }

if (Build.VERSION.SDK_INT</pre> 

自定義控件的著色

public class AppCompatView extends View implements TintableBackgroundView {

private TintInfo mTintInfo;

public AppCompatView(Context context) {
    this(context, null);
}

public AppCompatView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public AppCompatView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    EmBackgroundTintHelper.loadFromAttributes(this, attrs, defStyleAttr);
    init();
}

private void init() {
    mTintInfo = new TintInfo();
    mTintInfo.mHasTintList = true;
}

@Override
public void setSupportBackgroundTintList(ColorStateList tint) {
    EmBackgroundTintHelper.setSupportBackgroundTintList(this, mTintInfo,tint);
}

@Nullable
@Override
public ColorStateList getSupportBackgroundTintList() {
    return EmBackgroundTintHelper.getSupportBackgroundTintList(mTintInfo);
}

@Override
public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
    EmBackgroundTintHelper.setSupportBackgroundTintMode(this, mTintInfo, tintMode);
}

@Nullable
@Override
public PorterDuff.Mode getSupportBackgroundTintMode() {
    return EmBackgroundTintHelper.getSupportBackgroundTintMode(mTintInfo);
}

}</pre>

最后

最后打個小廣告,并附上 Github 及我的 Blog

 本文由用戶 FredaRule 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!