Android如何通过代码为TextView设置tint并解决不生效问题
Android动态设置ImageView/TextView状态Tint不生效问题解决方案
问题场景
Android开发中通过代码动态配置ColorStateList,给ImageView和TextView设置tint,实现选中/未选中状态下自动切换颜色的效果:
- ImageView调用
setImageTintList()设置后可正常生效 - TextView调用
setCompoundDrawableTintList()设置始终不生效,视图始终加载XML布局文件中预定义的tintList配置
问题复现代码
// 自定义状态颜色集合 myColorStateList = new ColorStateList( new int[][]{ new int[]{-android.R.attr.state_selected}, // 未选中状态 new int[]{android.R.attr.state_selected} // 选中状态 }, new int[]{ ContextCompat.getColor(mContext, R.color.red), // 未选中为红色 ContextCompat.getColor(mContext, R.color.blue) // 选中为蓝色 } ); // ImageView设置正常生效 myImageView.setImageTintList(myColorStateList); // TextView设置无效,始终读取XML中配置的tint myTextView.setCompoundDrawableTintList(myColorStateList);
已验证无效的方案
- 调用
myTextView.setCompoundDrawableTintList(null),运行效果无变化 - 调用
myTextView.setTextColor(null),运行效果无变化 - 调用
myTextView.setCompoundDrawableTintMode(PorterDuff.Mode.DST),运行效果无变化
根因说明
TextView复合drawable的tint逻辑存在系统版本碎片化问题:
- 如果XML布局中提前给TextView配置了
android:drawableTint/app:drawableTint属性,API23-API25版本的框架实现会将该tint标记为静态配置,直接调用setCompoundDrawableTintList()无法覆盖缓存的配置 - 框架原生方法不会主动刷新已绑定到TextView的复合drawable的tint状态,新设置的tintList不会立即应用到已加载的drawable上
- 原生TextView的tint优先级逻辑中,XML静态配置优先级高于代码动态设置,AppCompat组件修复了该优先级问题
可行实现代码
优先使用AppCompatTextView替代原生TextView(兼容库修复了绝大多数系统版本tint相关bug),按以下步骤设置即可同时兼容ImageView和TextView的动态tint配置:
// 1. 取出TextView当前绑定的四个方向复合drawable Drawable[] compoundDrawables = myTextView.getCompoundDrawables(); // 2. 清空原有复合drawable,清除XML配置的tint缓存 myTextView.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null); // 3. 设置tint // ImageView设置逻辑 if (myImageView instanceof AppCompatImageView) { ((AppCompatImageView) myImageView).setSupportImageTintList(myColorStateList); } else { myImageView.setImageTintList(myColorStateList); } // TextView设置逻辑 if (myTextView instanceof AppCompatTextView) { AppCompatTextView tv = (AppCompatTextView) myTextView; // 重置tint混合模式为默认值,避免之前的mode配置干扰 tv.setSupportCompoundDrawableTintMode(PorterDuff.Mode.SRC_IN); // 用兼容库方法设置tintList,优先级高于XML静态配置 tv.setSupportCompoundDrawableTintList(myColorStateList); } else { myTextView.setCompoundDrawableTintMode(PorterDuff.Mode.SRC_IN); myTextView.setCompoundDrawableTintList(myColorStateList); } // 4. 重新绑定原有的复合drawable myTextView.setCompoundDrawablesWithIntrinsicBounds( compoundDrawables[0], compoundDrawables[1], compoundDrawables[2], compoundDrawables[3] ); // 5. 刷新视图状态,让tint立即匹配当前选中状态 myImageView.refreshDrawableState(); myTextView.refreshDrawableState();
注意事项
- 对于需要动态修改复合drawable tint的TextView,不要在XML布局中写死
drawableTint相关属性,避免静态配置干扰动态设置 - 如果需要给TextView文字本身配置状态切换颜色,直接调用
setTextColor(myColorStateList)即可,该方法和复合drawable的tint配置互相独立 - 所有需要支持tint动态配置的视图,优先替换为AppCompat系列组件,减少系统版本碎片化带来的适配问题
内容的提问来源于stack exchange,提问作者Sushwanth
相关产品推荐
相关产品推荐

