1 学习tint的目的
tint可以帮助我们一张图实现各种变色,也就是说可以非常容易改变某个icon的颜色,同样的也能减少我们apk的体积(原本需要多张图片的,现在可能一张就够了)。
该图为tint效果图: 图片来源http://andraskindler.com/blog/2015/tinting_drawables
对于学习tint,我们有两个目的:
矢量图适配所有颜色(妈妈再也不要担心我找图了)。 更优雅的selector实现方式。
2一张矢量图适配所有颜色
如何在代码中实现下图效果
方法很简单直接看代码
一个为原图效果,一个通过android:tint="@color"改变了颜色。 至于原理不做过多说明,有兴趣看看源码比较简单,也可以参考一下官网或者下面这篇文章:
https://segmentfault.com/a/1190000003038675?_ea=281641
DrawableCompat类:
是Drawable的向下兼容类,我们为了在6.0一下兼容tint属性而使用的,有兴趣的看看源码哦,也是很简单的一个兼容类。
wrap方法:使用tint就必须调用该方法对Drawable进行一次包装。 mutate方法:(个人简单的理解就是类似于对象的深拷贝与浅拷贝),如果不调用该方法,我们进行操作的就是原drawable,着色之后原drawable也改变的,所有两个ImageView都会显示着色之后的drawable。调用mutate后会对ConstantState进行一次拷贝,详情可看源码,或者参考该文: http://www.race604.com/tint-drawable/ 。
恩,目的一基本完成了,我们来看目的二。
3更优雅的实现selector 为了更加优雅的使用selector可谓是踩了很多坑啊,但是实践才是检验真理的唯一标准,遇到坑就多去看看源码。
以前使用selector是这样的:
所以咯,我们需要在mipmap中放置两张图片。
但是目的一中我们知道一张矢量图是能适配出所有颜色的。所以我们开始踩坑。
我们可以在color中定义一个selector,然后设置tint属性。
目的为了实现点击图标换色的效果。
3.1 第一次尝试
color/icon.xml
设置后你会发现,并没有效果啊!这是为什么呢,我们看看BitmapDrawable源码吧。
DEBUG发现updateTintFilter()方法已经执行,为什么没有效果呢? 进一步DEBUG发现界面未刷新,invalidateSelf()方法未调用,ImageView的onDraw()方法未执行,所以Drawable的draw()方法也未执行。所以暂时这种方法是行不通的。
3.2 第二次尝试
于是我们使用StateListDrawable,那么先在xml中试试可行性吧。
我们在drawable目录下icon.xml中两种状态都设置的同一张图。 恩,到这里你就会惊人的发现,效果出来了(点击切换颜色)!
但是很遗憾6.0以下会直接crash的,因为不兼容,所以我们为了兼容性,可以考虑在java代码中设置。
按照这个思路撸出代码。
代码是不是看起来还挺复杂,不过在通过代码编写selector时都是类似上面的代码,还是值得研究一番。
恩,效果出来了,具体为什么可以去看看StateListDrawable源码,然后自己DEBUG一下。
到这里踩坑完成了。更优雅的实现selector,既减少了apk大小又节约了内存。
最后总结下,默认情况下(积极使用AppCompatActivity)tint属性是兼容低版本的,而通过selector的方式只能在高版本中有效果,所以我们给出了代码去创建selector以保证其能够对低版本进行适配。
这里会不会有疑问,android:tint怎么做到兼容低版本呢?该文探究 LayoutInflater setFactory给出了解释。
|