Android L 的 Tint(着色)
Tint 是什么?
Tint 翻譯為著色。
著色,著什么色呢,和背景有關?當然是著背景的色。當我們開發 App 的時候,如果使用了 Theme.AppCompat 主題的時候,會發現 ActionBar 或者 Toolbar 及相應的控件的顏色會相應的變成我們在 Theme 中設置的 colorPrimary, colorPrimaryDark, colorAccent 這些顏色,這是為什么呢,這就全是 Tint 的功勞了!
這樣做有什么好處呢?好處就是你不必再老老實實的打開 PS 再制作一張新的資源圖。而且大家都知道 apk 包最大的就是圖片資源了,這樣減少不必要資源圖,可以極大的減少了我們的 apk 包的大小。
實現的方式就是用一個顏色為我們的背景圖片設置 Tint(著色)。
看看即將發布的SegmentFault for Android 2.7中,發布問題功能,這個EditText的顏色和我們的主要顏色相同。它利用了TintManager這個類,為自己的背景進行著色(綠色)。
那么這個原始圖是什么樣子呢?我們從appcompat-v7包中找到了這個圖,是一個.9圖,樣子如下:
其實它只是一個黑色的條,通過綠色的著色,變成了一個綠色的條。 就是這樣的設計方式,使得我們在Material Design中省了多少資源文件呀!
例子:
大家可以看上面再張圖,這個是做的一個應用“小白球”,如圖 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進行應用}} }然后我們進入tintViewBackground看下TintManager里面的源碼
public static void tintViewBackground(View view, TintInfo tint) {final Drawable background = view.getBackground();if (tint.mHasTintList) {//如果設置了tint的話,對背景設置PorterDuffColorFiltersetPorterDuffColorFilter(background,tint.mTintList.getColorForState(view.getDrawableState(),tint.mTintList.getDefaultColor()),tint.mHasTintMode ? tint.mTintMode : null);} else {background.clearColorFilter();}if (Build.VERSION.SDK_INT <= 10) {// On Gingerbread, GradientDrawable does not invalidate itself when it's ColorFilter// has changed, so we need to force an invalidationview.invalidate();} }private static void setPorterDuffColorFilter(Drawable d, int color, PorterDuff.Mode mode) {if (mode == null) {// If we don't have a blending mode specified, use our defaultmode = DEFAULT_MODE;}// First, lets see if the cache already contains the color filterPorterDuffColorFilter filter = COLOR_FILTER_CACHE.get(color, mode);if (filter == null) {// Cache miss, so create a color filter and add it to the cachefilter = new PorterDuffColorFilter(color, mode);COLOR_FILTER_CACHE.put(color, mode, filter);}// 最最重要,原來是對background drawable設置了colorFilter 完成了我們要的功能。d.setColorFilter(filter); }
以上是對API21以下的兼容。
如果我們要實現自己的AppCompat組件實現tint的一些特性的話,我們就可以指定好ColorStateList,利用TintManager對自己的背景進行著色,當然需要對外開放設置的接口的話,我們還要實現TintableBackgroundView接口,然后用ViewCompat.setBackgroundTintList進行設置,這樣能完成對v7以上所有版本的兼容。
實例
比如我現在要對一個自定義組件實現對Tint的支持,其實只用繼承下,加一些代碼就好了,代碼如下(幾乎通用):
public class AppCompatFlowLayout extends FlowLayout implements TintableBackgroundView {private static final int[] TINT_ATTRS = {android.R.attr.background};private TintInfo mInternalBackgroundTint;private TintInfo mBackgroundTint;private TintManager mTintManager;public AppCompatFlowLayout(Context context) {this(context, null);}public AppCompatFlowLayout(Context context, AttributeSet attributeSet) {this(context, attributeSet, 0);}public AppCompatFlowLayout(Context context, AttributeSet attributeSet, int defStyle) {super(context, attributeSet, defStyle);if (TintManager.SHOULD_BE_USED) {TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attributeSet,TINT_ATTRS, defStyle, 0);if (a.hasValue(0)) {ColorStateList tint = a.getTintManager().getTintList(a.getResourceId(0, -1));if (tint != null) {setInternalBackgroundTint(tint);}}mTintManager = a.getTintManager();a.recycle();}}private void applySupportBackgroundTint() {if (getBackground() != null) {if (mBackgroundTint != null) {TintManager.tintViewBackground(this, mBackgroundTint);} else if (mInternalBackgroundTint != null) {TintManager.tintViewBackground(this, mInternalBackgroundTint);}}}@Overrideprotected void drawableStateChanged() {super.drawableStateChanged();applySupportBackgroundTint();}private void setInternalBackgroundTint(ColorStateList tint) {if (tint != null) {if (mInternalBackgroundTint == null) {mInternalBackgroundTint = new TintInfo();}mInternalBackgroundTint.mTintList = tint;mInternalBackgroundTint.mHasTintList = true;} else {mInternalBackgroundTint = null;}applySupportBackgroundTint();}@Overridepublic void setSupportBackgroundTintList(ColorStateList tint) {if (mBackgroundTint == null) {mBackgroundTint = new TintInfo();}mBackgroundTint.mTintList = tint;mBackgroundTint.mHasTintList = true;applySupportBackgroundTint();}@Nullable@Overridepublic ColorStateList getSupportBackgroundTintList() {return mBackgroundTint != null ? mBackgroundTint.mTintList : null;}@Overridepublic void setSupportBackgroundTintMode(PorterDuff.Mode tintMode) {if (mBackgroundTint == null) {mBackgroundTint = new TintInfo();}mBackgroundTint.mTintMode = tintMode;mBackgroundTint.mHasTintMode = true;applySupportBackgroundTint();}@Nullable@Overridepublic PorterDuff.Mode getSupportBackgroundTintMode() {return mBackgroundTint != null ? mBackgroundTint.mTintMode : null;} }-
Github:https://github.com/iQuick/AndroidTint
總結
以上是生活随笔為你收集整理的Android L 的 Tint(着色)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 五大常用算法(一) - 分治算法
- 下一篇: Android代码优化——使用Andro