Android--安卓着色器(tint)使用实践
来源:互联网 发布:二战苏联单兵装备知乎 编辑:程序博客网 时间:2024/05/17 04:38
安卓着色器(tint)使用实践。
学习tint的目的:
1.一张矢量图适配所有颜色(妈妈再也不要担心我找图了)。
2.更优雅的selector实现方式。
小试牛刀,一张矢量图适配所有颜色。
如何在代码中实现下图效果
方法一: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,将不会触发刷新,具体看源码,本篇侧重于实践。)
恩,到这里你就会惊人的发现,效果出来了!(点击后变色)
但是很遗憾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大小又节约了内存。
源码在这里,更多踩坑请点击...
- 安卓着色器(tint)使用实践。
- Android--安卓着色器(tint)使用实践
- 安卓着色器Tint的使用
- Android 着色器 Tint
- Android 着色器tint
- Android-Tint使用实践
- Android 着色器 Tint 研究
- Android 着色器 Tint 研究
- 从使用到源码,细说 Android 中的 tint 着色器
- Android着色器tint相关剖析
- Android 图片着色 Tint 详解
- android tint着色器(蒙层/阴影等)
- Android 低版本实现Tint--着色功能
- 浅谈 Android L 的 Tint(着色)
- 浅谈 Android L 的 Tint(着色)
- 浅谈 Android L 的 Tint(着色)
- android tint selector 使用
- Android中Tint使用
- Linux下Tomcat安装
- Struts(S2-037)远程代码执行
- RxJava进阶之源码分析map() 操作符分析
- usb 无法弹出,查看占用
- Android ListView实现通讯录的实例
- Android--安卓着色器(tint)使用实践
- ubuntu/var/log/下各个日志文件
- Android常用adb命令总结
- redis info 参数详解
- 基于maven的springMvc+Mybatis,搭建项目的时候发现一些问题这里例举下
- 网络服务器设计
- 程序员、技术领导、管理者各有烦恼,你占了几条?
- 数值数据类型及表示
- springmvc和Angularjs 跨域传输 jsonp