安卓着色器(tint)使用实践。

学习tint的目的:

1.一张矢量图适配所有颜色(妈妈再也不要担心我找图了)。
2.更优雅的selector实现方式。
[图片上传失败...(image-3878ff-1510058207692)]](http://upload-images.jianshu.io/upload_images/1757399-c52e20090d67b2e5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

小试牛刀,一张矢量图适配所有颜色。

如何在代码中实现下图效果


效果1

方法一:xml
方法很简单直接看代码

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/image"
        android:src="@mipmap/icon"
        android:clickable="true"
        />
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/image2"
        android:src="@mipmap/icon"
        android:tint="#FFCDD2"
        android:clickable="true"
        />

用到的属性android:tint="@color"
至于原理不做过多说明,有兴趣看看源码比较简单,也可以参考一下官网。
方法二:代码实现

        Drawable drawable = ContextCompat.getDrawable(this,R.mipmap.icon);
        Drawable.ConstantState state = drawable.getConstantState();
        Drawable drawable1 = DrawableCompat.wrap(state == null ? drawable : state.newDrawable()).mutate();
        drawable1.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
        DrawableCompat.setTint(drawable,ContextCompat.getColor(this,R.color.pink));
        imageView.setImageDrawable(drawable);
        imageView1.setImageDrawable(drawable1);

DrawableCompat类:是Drawable的向下兼容类,我们为了在6.0一下兼容tint属性而使用的,有兴趣的看看源码哦,也是很简单的一个兼容类。

wrap方法:使用tint就必须调用该方法对Drawable进行一次包装。

mutate方法:(个人简单的理解就是类似于对象的深拷贝与浅拷贝),如果不调用该方法,我们进行操作的就是原drawable,着色之后原drawable也改变的,所有两个ImageView都会显示着色之后的drawable。调用mutate后会对ConstantState进行一次拷贝,详情可看源码,以及参考

恩,目的一基本完成了,我们来看目的二。

更加优雅的使用selector
第一次尝试

为了更加优雅的使用selector可谓是踩了很多坑啊,但是实践才是检验真理的唯一标准,遇到坑就多去看看源码。
以前使用selector是这样的。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@mipmap/icon_pressed"></item>
    <item android:drawable="@mipmap/icon_normal"></item>
</selector>

所以咯,我们需要在mipmap中放置两张图片,但是目的一中我们知道一张矢量图是能适配出所有颜色的。所以我们开始踩坑。
我们可以在color中定义一个selector,然后设置tint属性。

//color/icon.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:color="@color/pink" ></item>
    <item android:color="@color/pink1"></item>
</selector>

<ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/image"
        android:src="@mipmap/icon"
        android:tint="@color/icon"
        android:clickable="true"
        />

设置后你会发现,并没有效果啊!这是为什么呢,我们看看BitmapDrawable源码吧。

    @Override
    protected boolean onStateChange(int[] stateSet) {
        final BitmapState state = mBitmapState;
        if (state.mTint != null && state.mTintMode != null) {
            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
            return true;
        }
        return false;
    }

DEBUG发现updateTintFilter()方法已经执行,为什么没有效果呢?
进一步DEBUG发现界面未刷新,invalidateSelf()方法未调用,ImageView的onDraw()方法未执行,所以Drawable的draw()方法也未执行。所以暂时这种方法是行不通的。(但是在java逻辑代码中设置了在6.0以下是可以实现的,具体为什么我也有点纳闷…可以去看看我的demo)

第二次尝试

于是我们使用StateListDrawable,那么先在xml中试试可行性吧。

//drawable/icon.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:color="@drawable/icon" ></item>
    <item android:color="@color/pink1"></item>
</selector>

<ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/image"
        android:src="@drawable/icon"
        android:tint="@color/icon"
        android:clickable="true"
        />

我们在drawable目录下icon.xml中两种状态都设置的同一张图。(为什么要设置同一张图是有根据的,因为DrawableStateList源码中,如果你当然状态未单独设置drawable,将不会触发刷新,具体看源码,本篇侧重于实践。)
恩,到这里你就会惊人的发现,效果出来了!(点击后变色)

效果2.gif

但是很遗憾6.0以下会直接crash的,因为不兼容,所以我们必须在java代码中设置。按照这个思路撸出代码。

    Drawable drawable = ContextCompat.getDrawable(this,R.mipmap.icon);
    int[] colors = new int[] { ContextCompat.getColor(this,R.color.pink),ContextCompat.getColor(this,R.color.pink1)};
    int[][] states = new int[2][];
    states[0] = new int[] { android.R.attr.state_pressed};
    states[1] = new int[] {};
    ColorStateList colorList = new ColorStateList(states, colors);
    StateListDrawable stateListDrawable = new StateListDrawable();
    stateListDrawable.addState(states[0],drawable);//注意顺序
    stateListDrawable.addState(states[1],drawable);
    Drawable.ConstantState state = stateListDrawable.getConstantState();
    drawable = DrawableCompat.wrap(state == null ? stateListDrawable : state.newDrawable()).mutate();
    DrawableCompat.setTintList(drawable,colorList);
    imageView.setImageDrawable(drawable);

(代码有点多,但是这样做是很值得的。其实这样做感觉更符合逻辑一点,不过期间踩了很多坑,特别是在做6.0和6.0以下适配的时候)
恩,效果出来了,具体原因可以去看看StateListDrawable源码,然后自己DEBUG一下。
到这里踩坑完成了。更优雅的实现selector,既减少了apk大小又节约了内存。

源码在这里,更多踩坑请点击...

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容