通信技术服务 發表於 2025-11-25 08:39:22

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

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>1. 背景</li><li>2. 使用 Tint 动态着色</li><ul class="second_class_ul"><li>2.1 使用方式</li><li>2.2 原理分析</li></ul><li>3. 注意事项</li><ul class="second_class_ul"><li>3.1 同时设置 ImageView 与 Drawable,Drawable 的设置会失效</li></ul></ul></div><p class="maodian"></p><h2>1. 背景</h2>
<p>在 App 当中,会有很多 <strong>形状相同、颜色不同</strong> 的 Icon。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202511/2025112583802729.jpg" /></p>
<p>例如上图这个场景,是筛选项的 icon,对应的代码可能为:</p>
<ul><li>Xml 中初始化颜色为黑色</li></ul>
<div class="jb51code"><pre class="brush:xml;">&lt;ImageView
    ...
    android:src="@drawable/icon_filter_black" /&gt;
</pre></div>
<ul><li>代码中根据筛选状态,切换不同颜色的 icon</li></ul>
<div class="jb51code"><pre class="brush:java;">// XXXFragment.kt

imageView.setImageDrawable(
    if (isSelect) {
      // 筛选后为橙色
      resources.getDrawable(R.drawable.icon_filter_orange);
    } else {
      // 未筛选为黑色
      resources.getDrawable(R.drawable.icon_filter_black);
    }
)
</pre></div>
<p>如果为每种颜色的 Icon 都保存一张图片,会增加包体积。同时,会增加设计的工作负担。有没有什么办法可以做到只需要一张图片,然后动态的着色呢?</p>
<p class="maodian"></p><h2>2. 使用 Tint 动态着色</h2>
<p class="maodian"></p><h3>2.1 使用方式</h3>
<p>有以下几种方式:</p>
<ol><li>xml 中设置</li></ol>
<div class="jb51code"><pre class="brush:xml;">&lt;ImageView
    ...
    android:src="@drawable/icon_filter"
    app:tint="@color/black"
    /&gt;
</pre></div>
<ol start="2"><li>代码中为 ImageView 设置</li></ol>
<div class="jb51code"><pre class="brush:java;">imageView.imageTintList = ColorStateList(...)
</pre></div>
<ol start="3"><li>代码中直接为 Drawable 设置</li></ol>
<div class="jb51code"><pre class="brush:java;">val drawable = resources.getDrawable(R.drawable.icon_filter)
drawable.setTint = Color.BLACK

imageView.setImageDrawable(drawable)
</pre></div>
<p>设置 tint 后,绘制时就会用 tint 的颜色渲染 icon。这样,就算只有一张图片,也可以渲染为多种颜色。很大程度的节省了包体积。</p>
<p class="maodian"></p><h3>2.2 原理分析</h3>
<ul><li>ImageView 会将 Tint 传给 Drawable</li></ul>
<div class="jb51code"><pre class="brush:java;"> // ImageView.java
public void setImageTintList(@Nullable ColorStateList tint) {
    mDrawableTintList = tint;
    mHasDrawableTint = true;
   
    applyImageTint();
}

private void applyImageTint() {
    if (mDrawable != null &amp;&amp; (mHasDrawableTint || mHasDrawableBlendMode)) {
      mDrawable = mDrawable.mutate();
      
      if (mHasDrawableTint) {
            mDrawable.setTintList(mDrawableTintList); // 将 tint 传递给 Drawable!
      }
      // ...
    }
}
</pre></div>
<ul><li>Drawable 在 <strong>收到 Tint</strong> 时会创建 <strong>ColorFilter</strong>,在 draw 时会用它做颜色过滤处理。这里拿 VectorDrawable 举例:</li></ul>
<div class="jb51code"><pre class="brush:java;">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 ;
    }
}
</pre></div>
<p class="maodian"></p><h2>3. 注意事项</h2>
<p class="maodian"></p><h3>3.1 同时设置 ImageView 与 Drawable,Drawable 的设置会失效</h3>
<ul><li>例如,我们在 xml 中设置 tint 为黑色</li></ul>
<div class="jb51code"><pre class="brush:xml;">&lt;ImageView
    ...
    android:src="@drawable/icon_filter"
    app:tint="@color/black"
    /&gt;
</pre></div>
<ul><li>在代码中,为 Drawable 设置为黄色</li></ul>
<div class="jb51code"><pre class="brush:plain;">val drawable = resources.getDrawable(R.drawable.icon_filter)
drawable.setTint = Color.YELLOW

imageView.setImageDrawable(drawable)
</pre></div>
<ul><li>此时,对 Drawable 的设置是不生效的,因为此时 ImageView.setImageDrawable 会覆盖掉 Drawable 自身的 tint</li></ul>
<div class="jb51code"><pre class="brush:java;">// ImageView.kt

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

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

private void applyImageTint() {
    if (mHasDrawableTint) {
      mDrawable.setTintList(mDrawableTintList) ;
    }
}
</pre></div>
<ul><li>所以如果同时设置 ImageView 与 Drawable 的 tint,要关注覆盖问题。</li></ul>
<p>到此这篇关于Android使用Tint为图标Icon动态着色的操作方法的文章就介绍到这了,更多相关Android Tint为Icon动态着色内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>android实现icon动态旋转效果</li><li>使用android studio开发工具编译GBK转换三方库iconv的方法</li><li>解决Android SearchView不显示搜索icon的问题</li><li>Android Studio报:“Attribute application@theme or @ icon ”问题的解决</li><li>Android iconify 使用详解</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: Android使用Tint为图标Icon动态着色的操作方法