Android使用Tint为图标Icon动态着色的操作方法

 更新时间:2025年11月25日 08:39:22   作者:kerli  
本文介绍了在Android中使用Tint为图标动态着色的方法,可以通过xml或代码设置Tint属性,从而实现单张图片的动态着色,节省包体积,需要注意的是,同时设置ImageView与Drawable的Tint时,要关注覆盖问题,需要的朋友可以参考下

1. 背景

在 App 当中,会有很多 形状相同、颜色不同 的 Icon。

例如上图这个场景,是筛选项的 icon,对应的代码可能为:

  • Xml 中初始化颜色为黑色
<ImageView
    ...
    android:src="@drawable/icon_filter_black" />
  • 代码中根据筛选状态,切换不同颜色的 icon
// XXXFragment.kt

imageView.setImageDrawable(
    if (isSelect) {
        // 筛选后为橙色
        resources.getDrawable(R.drawable.icon_filter_orange);
    } else {
        // 未筛选为黑色
        resources.getDrawable(R.drawable.icon_filter_black);
    }
)

如果为每种颜色的 Icon 都保存一张图片,会增加包体积。同时,会增加设计的工作负担。有没有什么办法可以做到只需要一张图片,然后动态的着色呢?

2. 使用 Tint 动态着色

2.1 使用方式

有以下几种方式:

  1. xml 中设置
<ImageView
    ...
    android:src="@drawable/icon_filter" 
    app:tint="@color/black"
    />
  1. 代码中为 ImageView 设置
imageView.imageTintList = ColorStateList(...)
  1. 代码中直接为 Drawable 设置
val drawable = resources.getDrawable(R.drawable.icon_filter)
drawable.setTint = Color.BLACK

imageView.setImageDrawable(drawable)

设置 tint 后,绘制时就会用 tint 的颜色渲染 icon。这样,就算只有一张图片,也可以渲染为多种颜色。很大程度的节省了包体积。

2.2 原理分析

  • ImageView 会将 Tint 传给 Drawable
 // ImageView.java
public void setImageTintList(@Nullable ColorStateList tint) {
    mDrawableTintList = tint;
    mHasDrawableTint = true;
    
    applyImageTint();
}

private void applyImageTint() {
    if (mDrawable != null && (mHasDrawableTint || mHasDrawableBlendMode)) {
        mDrawable = mDrawable.mutate();
        
        if (mHasDrawableTint) {
            mDrawable.setTintList(mDrawableTintList); // 将 tint 传递给 Drawable!
        }
        // ...
    }
}
  • Drawable 在 收到 Tint 时会创建 ColorFilter,在 draw 时会用它做颜色过滤处理。这里拿 VectorDrawable 举例:
public class VectorDrawable extends Drawable {
    private BlendModeColorFilter mBlendModeColorFilter ;
    
    @Override
    public void setTintList(ColorStateList tint) {
        // 使用 tint 创建 ColorFilter
        updateColorFilters(... , tint) ;
    }
    
    private void updateColorFilters(@Nullable BlendMode blendMode , ColorStateList tint) {
        // ...
    mBlendModeColorFilter = updateBlendModeFilter(mBlendModeColorFilter , tint , blendMode) ;
    }
    
    @Override
    public void draw(Canvas canvas) {
        // 绘制时,如果外部没有设置 mColorFilter,则使用 mBlendModeColorFilter
        final ColorFilter colorFilter = (mColorFilter == null ? mBlendModeColorFilter : mColorFilter) ;
        // ...
    }
}

public abstract class Drawable {
    @Nullable 
    BlendModeColorFilter updateBlendModeFilter(@Nullable ColorStateList tint , ... ) {
        // ... 
        final int color = tint.getColorForState(getState() , Color.TRANSPARENT) ;
    
        if (blendFilter == null || blendFilter.getColor() != color
                || blendFilter.getMode() != blendMode) {
            return new BlendModeColorFilter(color , blendMode) ;
        }
        
        return blendFilter ;
    }
}

3. 注意事项

3.1 同时设置 ImageView 与 Drawable,Drawable 的设置会失效

  • 例如,我们在 xml 中设置 tint 为黑色
<ImageView
    ...
    android:src="@drawable/icon_filter"
    app:tint="@color/black"
    />
  • 在代码中,为 Drawable 设置为黄色
val drawable = resources.getDrawable(R.drawable.icon_filter)
drawable.setTint = Color.YELLOW

imageView.setImageDrawable(drawable)
  • 此时,对 Drawable 的设置是不生效的,因为此时 ImageView.setImageDrawable 会覆盖掉 Drawable 自身的 tint
// ImageView.kt

public void setImageDrawable(@Nullable Drawable drawable) {
    updateDrawable(drawable) ;
}

private void updateDrawable(Drawable d) {
    applyImageTint() ;
}

private void applyImageTint() {
    if (mHasDrawableTint) {
        mDrawable.setTintList(mDrawableTintList) ;
    }
}
  • 所以如果同时设置 ImageView 与 Drawable 的 tint,要关注覆盖问题。

到此这篇关于Android使用Tint为图标Icon动态着色的操作方法的文章就介绍到这了,更多相关Android Tint为Icon动态着色内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Android Dialog 动画实例详解

    Android Dialog 动画实例详解

    这篇文章主要介绍了Android Dialog 动画实例详解的相关资料,需要的朋友可以参考下
    2017-04-04
  • Android Studio实现简易进制转换计算器

    Android Studio实现简易进制转换计算器

    这篇文章主要为大家详细介绍了Android Studio实现简易进制转换计算器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • flutter text组件使用示例详解

    flutter text组件使用示例详解

    这篇文章主要为大家介绍了flutter text组件使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Android操作存放在assets文件夹下SQLite数据库的方法

    Android操作存放在assets文件夹下SQLite数据库的方法

    这篇文章主要介绍了Android操作存放在assets文件夹下SQLite数据库的方法,实例分析了Android操作SQLite数据库的相关技巧,需要的朋友可以参考下
    2015-06-06
  • Android模拟器最新检测方法详解

    Android模拟器最新检测方法详解

    这篇文章主要介绍了Android模拟器的检测方法,在Android开发过程中,防作弊一直是老生常谈的问题,而模拟器的检测往往是防作弊中的重要一环,接下来我们来讲解有关于模拟器的检测方法,需要的朋友可以参考下
    2024-02-02
  • Android上实现RTSP服务器的方法

    Android上实现RTSP服务器的方法

    在Android平台实现RTSP服务器是一项挑战性任务,旨在无需部署独立的RTSP/RTMP服务,通过内置轻量级RTSP服务,实现本地音视频数据的对外共享,本文介绍Android上实现RTSP服务器的方法,感兴趣的朋友一起看看吧
    2024-11-11
  • Android上使用jspf插件框架的方法

    Android上使用jspf插件框架的方法

    这篇文章主要介绍了Android上使用jspf插件框架的方法,实例分析了jspf插件框架的功能与使用技巧,需要的朋友可以参考下
    2015-06-06
  • Android开发重写Animation实现下拉图片后弹射回去效果示例

    Android开发重写Animation实现下拉图片后弹射回去效果示例

    这篇文章主要介绍了Android开发重写Animation实现下拉图片后弹射回去效果,结合实例形式分析了Android自定义类继承Animation实现图片弹射效果的相关操作技巧,需要的朋友可以参考下
    2017-10-10
  • Gradle 依赖切换源码实践示例详解

    Gradle 依赖切换源码实践示例详解

    这篇文章主要为大家介绍了Gradle 依赖切换源码实践示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Android中判断是否有前置摄像头、后置摄像头的方法

    Android中判断是否有前置摄像头、后置摄像头的方法

    这篇文章主要介绍了Android中判断是否有前置摄像头、后置摄像头的方法,本文直接给出实现代码,需要的朋友可以参考下
    2015-01-01

最新评论