Android 中 tint(着色)是一个非常强大的功能,它可以让你用一套图标资源适配多种颜色(例如夜间模式、点击变色、主题切换),而无需让 UI 切多套图。这里是Android 中 Tint 的全方位用法指南,涵盖了常用控件、特殊控件、代码实现以及进阶配置。
一、 常用控件的 Tint 用法
1. ImageView (图标着色)
最常用的场景,用于改变 src 图片的颜色。
-
XML:
xml<ImageView ... android:src="@drawable/ic_icon" app:tint="#FF0000" /> <!-- 推荐:兼容性更好 --> <!-- android:tint="#FF0000" 原生属性,但在某些版本可能有兼容问题 --> -
代码 (Kotlin):
kotlinimageView.setColorFilter(Color.RED) // 最简单 // 或者使用 Compat 库 (推荐) ImageViewCompat.setImageTintList(imageView, ColorStateList.valueOf(Color.RED))
2. View / ViewGroup (背景着色)
用于改变 background 的颜色,比如让一个圆角矩形背景变色,而不改变形状。
-
XML:
xml<Button ... android:background="@drawable/bg_rounded_gray" app:backgroundTint="#00FF00" /> <!-- 推荐使用 app: 前缀 --> -
代码 (Kotlin):
kotlinViewCompat.setBackgroundTintList(view, ColorStateList.valueOf(Color.BLUE))
3. TextView (复合图标着色)
用于改变 TextView 上下左右 (drawableLeft/drawableTop...) 图标的颜色。
-
XML (API 23+):
xml<TextView ... android:drawableTop="@drawable/ic_icon" android:drawableTint="#FF0000" /> -
兼容方案 (API < 23):
XML 中无法直接支持低版本,建议使用DrawableCompat在代码中处理,或者使用app:drawableTint(依赖最新 AppCompat/Material 库)。
二、 特殊控件的 Tint 用法
Android 为很多特定组件提供了专属的 tint 属性:
| 控件 | XML 属性 | 作用 |
|---|---|---|
| CheckBox / RadioButton | app:buttonTint |
改变勾选框/圆圈的颜色 |
| ProgressBar | android:progressTint |
改变进度条颜色 (API 21+) |
| ProgressBar (不确定) | android:indeterminateTint |
改变转圈圈加载动画的颜色 |
| SeekBar | android:thumbTint |
改变拖动滑块的颜色 |
| FloatingActionButton | app:backgroundTint |
改变悬浮按钮的底色 |
| MaterialButton | app:iconTint |
改变按钮内部图标的颜色 |
| BottomNavigationView | app:itemIconTint |
改变底部导航栏图标颜色 (通常配合 Selector) |
三、 进阶:Tint Mode (混合模式)
除了设置颜色,你还可以设置 Tint Mode 来决定颜色如何与图片融合。
属性:app:tintMode (或 android:tintMode)。
常见的模式如下(假设图片是黑色的,Tint 是红色的):
src_in(最常用)- 效果 :只保留图片形状,内容填充为 Tint 颜色。
- 场景:将图标完全变色(如把黑色返回箭头变成红色)。
src_atop- 效果:在图片不透明的地方绘制 Tint 颜色,透明的地方保持透明。如果图片本身有颜色(非纯黑),会覆盖在上面。
multiply(正片叠底)- 效果:颜色相乘。使得图片变暗。
screen(滤色)- 效果:让图片变亮。
四、 进阶:StateList (点击变色)
tint 不仅可以是一个颜色值,还可以是一个 ColorStateList(颜色选择器),实现点击时图标自动变色。
1. 创建 res/color/selector_tint.xml:
xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#FF0000" android:state_pressed="true" /> <!-- 按下变红 -->
<item android:color="#000000" /> <!-- 默认黑色 -->
</selector>
2. 在 ImageView 中使用:
xml
<ImageView
...
android:clickable="true"
android:src="@drawable/ic_icon"
app:tint="@color/selector_tint" /> <!-- 引用上面的 selector -->
五、 代码动态设置 Tint (通用方案)
如果你拿到了一个 Drawable 对象(比如从网络下载的,或者通过代码生成的),想要给它着色,需要注意使用 mutate(),否则可能会影响到所有使用该资源的地方。
标准写法:
kotlin
fun tintDrawable(drawable: Drawable, color: Int): Drawable {
// 1. 包装 Drawable (使其兼容低版本)
val wrappedDrawable = DrawableCompat.wrap(drawable).mutate()
// 2. 设置颜色
DrawableCompat.setTint(wrappedDrawable, color)
// 如果需要设置 Mode
// DrawableCompat.setTintMode(wrappedDrawable, PorterDuff.Mode.SRC_IN)
return wrappedDrawable
}
使用示例:
kotlin
val originalDrawable = ContextCompat.getDrawable(context, R.drawable.ic_icon)
imageView.setImageDrawable(tintDrawable(originalDrawable!!, Color.BLUE))
六、setColorFilter
简单来说,setColorFilter 就是给图片"加滤镜"。在 Android 开发中,它的核心作用是:**在不更换图片资源(PNG/JPG/Vector)的情况下,通过代码动态改变图片的显示颜色。**把它想象成给你的图片戴上了一副"有色眼镜"。
1. 核心用途
- 复用图标:你只需要切一张黑色的图标,就能通过它变成白色、红色、蓝色等。这样可以减小 APK 体积。
- 状态反馈:比如按钮被禁用时,用灰色滤镜让图片变暗;按钮按下时,加深颜色。
- 主题适配:根据用户选择的主题(白天/黑夜),动态修改图标颜色。
2. 代码示例
通常在 ImageView 或 Drawable 上调用。
场景 A:把图标变成纯色 (最常用)
比如你有一个黑色的搜索图标,想让它变成红色。
java
// Java
// PorterDuff.Mode.SRC_IN 是关键:它表示"取源图的形状,填入滤镜的颜色"
imageView.setColorFilter(Color.RED, PorterDuff.Mode.SRC_IN);
kotlin
// Kotlin
imageView.setColorFilter(Color.RED, PorterDuff.Mode.SRC_IN)
场景 B:清除滤镜 (恢复原样)
kotlin
imageView.clearColorFilter()
3. 核心参数:PorterDuff.Mode (混合模式)
setColorFilter 的强大之处在于第二个参数 PorterDuff.Mode,它决定了颜色 和原图怎么混合。
最常用的几种模式:
-
SRC_IN(重中之重)- 效果 :只保留图片的形状,完全填充成你设置的颜色。
- 用途:给图标换色(比如把黑色箭头变成白色箭头)。
- 这是 90% 的使用场景。
-
MULTIPLY(正片叠底)- 效果:颜色相乘,画面变暗。
- 用途:给背景图加一层遮罩,或者做"按下变暗"的效果。
-
SRC_ATOP- 效果:在不透明的地方上色,透明的地方保持透明。如果原图本身有彩色,会覆盖在上面。
4. setColorFilter vs Tint
你刚才问的 tint 和 setColorFilter 其实是表兄弟关系:
tint(XML 属性) :这是声明式 写法。你在 XML 里写app:tint,系统底层其实就是调用了setColorFilter相关的逻辑来渲染。setColorFilter(Java/Kotlin 方法) :这是命令式写法。你在代码逻辑里手动控制。
区别在于:
tint可以接受ColorStateList(比如点击变色 selector)。setColorFilter通常一次只设置一种固定的颜色(虽然也可以自己写逻辑监听点击事件来切换)。
总结
- 简单图标变色 :用
ImageView的app:tint。 - 背景变色 :用
app:backgroundTint。 - 点击变色 :
tint属性引用res/color/下的 selector 文件。 - 特定控件 :找对应的
buttonTint,thumbTint,iconTint等属性。 setColorFilter就是代码版的"图标染色剂"。 当你需要在代码里把一个图标改成别的颜色,又不想去切新图时,就用它。