Android 改变图片颜色几种方法

一、改变图片颜色的应用场景

一般来讲,同一个图标,在不同的页面和不同的场景,UI设计会用不同的颜色展示。或者不同的主题,使用不同的颜色,我们当然可以每种颜色都让UI切一张图,但一方面工作繁琐无比,另一方面应用场景狭隘,不利于扩展,每次有新设计或新主题时都需要新发布一个包。最后包体积也会大大增加,因而,同一张图标,通过代码实现动态更改颜色就有了必要。

本文中,主要讲图标颜色的更改,及一张图片整体处于同一色值时的修改。当然,若图标本身某些区域带着透明度,那么透明度也会延续下来,不会被更改。所以,如果图标是一张大块区域全不透明的图片,那么就不适用以下方案,因为使用后就是一张带图片轮廓的纯色色块。
如果是针对自己绘制的shape类型drawable,也可以通过代码动态设置其色值。
如果图片为svg时,我们也可以针对不同区域(path或group)设置不同的颜色,这需要我们对svg图的xml文件进行一定的了解,无法如同png类型一般直接设置色值即可。

二、更新图标颜色的方案

2.1 通过xml直接修改图标颜色

第一种 对src设置tint 这里需要注意tint因为版本兼容的原因要使用app标签

android:src="@drawable/ic_tag"
app:tint="@color/white"

第二种 对background设置backgroundTint

android:background="@drawable/ic_tag"
android:backgroundTint="@color/blue"

第三种 针对应用最低兼容安卓版本23的应用可设置foreground及foregroundTint

android:foreground="@drawable/ic_tag"
android:src="@drawable/ic_tag"
android:foregroundTint="@color/white"

  1. 由于foreground是前景,imageview并不会去获取其宽高设置为自身的宽高,所以在使用foreground时要么固定宽高,要么设置上src或background。并不推荐第三种方案来进行图标颜色的修改。
  2. 在设置tint的同时可以根据自己的需要去设置对应的tintMode,不同的mode,对图片所采用的颜色修改方式也不一样,如果只是纯粹将图标修改成另一个颜色,直接不进行设置使用默认即可

2.2 动态设置本地绘制shape类型drawable

一般来讲,本地绘制的shape都是设置到背景上,所以我们就可以进行以下设置:

val gd = view.background as? GradientDrawable
gd?.mutate() //重点注意,这里需要调用mutate()
//设置填充颜色,如果是纯色,直接设置color颜色即可,如果是渐变,则需要使用int数组设置到colors
gd?.colors = intArrayOf(bgColor,bgColor) 
//设置边框,第一个参数表示宽度,后面一个表示边框的颜色,有两种取值,直接color或colorStateList
gd?.setStroke(DisplayUtil.dip2px(1f), ColorStateList.valueOf(bgColor)) 

注:

  1. 由于Android系统的缓存,使用的资源resource drawable生成后,后续使用该资源都会直接调用该对象,如果我们在代码里面动态调整了该资源的颜色而没有设置了mutate(),那么后续调用的该资源色值都是动态设置后的颜色。但如果我们设置了mutate()则表示本次修改不进行缓存。同理,我们只要是针对drawable进行颜色的动态更新,都要考虑该方法的调用
  2. 对填充颜色的设置,需要注意纯色设置和渐变色设置,分别是color和colors,对应的参数分别是@ColorInt int color和@ColorInt int[] colors

2.3 代码动态设置图片颜色

第一种 对imageview设置colorfilter

imageview.setColorFilter(Color.parseColor(“#de1212”))

第二种 对imageview设置imageTintList

imageview.imageTintList = ColorStateList.valueOf(colorInt)

同xml,这里也可以设置backgroundTintList = ColorStateList.valueOf(colorInt)
如果某些控件图标是button(CheckBox),可使用buttonTintList = iconsColorStates
针对textview的drawable可使用:

textView.compoundDrawables.forEach {
    
    
            it?.mutate()
            it?.setTintList(ColorStateList.valueOf(Color.parseColor("#02724E")).withAlpha(153)) //设置带透明度的颜色
}

注:
关于ColorStateList,如果只是单纯的某个颜色就可以直接使用ColorStateList.valueOf(colorInt),如果想针对不同的状态设置不同的颜色,则可以用ColorStateList(int[][] states, @ColorInt int[] colors)进行设置。
例如:
ColorStateList(arrayOf(intArrayOf(-android.R.attr.state_checked),intArrayOf(android.R.attr.state_checked)), intArrayOf(iconRgb, iconSelectRgb))

拓展一下

ColorStateList可以设置不同状态下的颜色,那么有没有不同状态下使用不同的图标呢,当然是有的:StateListDrawable,它的使用方式类似ColorStateList,例如:

val stateListDrawable = StateListDrawable()
//按下背景 后一个参数为drawable类型
stateListDrawable.addState(intArrayOf(android.R.attr.state_pressed), pressBackGroundDrawable)
//选中背景
stateListDrawable.addState(intArrayOf(android.R.attr.state_selected), selectBackGroundDrawable)
//默认背景
stateListDrawable.addState(intArrayOf(), gradientDrawable)
view.background = stateListDrawable

上面不同状态所使用的drawable当然也可以运用上面列举的方法进行动态设置颜色。

2.4 对svg图进行动态颜色修改

有这样一张svg图,xml如下

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="25dp"
    android:height="25dp"
    android:viewportWidth="1024"
    android:viewportHeight="1024">
    <path
        android:name="border"
        android:fillColor="#FFFFFF"
        android:pathData="M512,0c255.41,0 462.45,207.05 462.45,462.45s-207.05,462.45 -462.45,462.45S49.55,717.86 49.55,462.45 256.59,0 512,0zM512,66.06C293.1,66.06 115.61,243.55 115.61,462.45s177.48,396.39 396.39,396.39 396.39,-177.48 396.39,-396.39S730.9,66.06 512,66.06z" />
    <path
        android:name="solid"
        android:fillColor="#22C96A"
        android:pathData="M512,66.06c218.9,0 396.39,177.48 396.39,396.39s-177.48,396.39 -396.39,396.39S115.61,681.36 115.61,462.45 293.1,66.06 512,66.06z" />
    <path
        android:name="center"
        android:fillColor="#FAFFFC"
        android:pathData="M444.12,534.66l237.47,-237.44a48.36,48.36 0,0 1,68.54 0.13c18.96,18.96 18.96,49.71 0.13,68.54l-268.98,268.95c-8.92,8.92 -20.38,13.64 -32.04,14.14a47.57,47.57 0,0 1,-39.21 -13.48l-136.36,-136.36a47.5,47.5 0,0 1,0.1 -67.39,47.86 47.86,0 0,1 67.39,-0.1l102.96,102.99z" />
</vector>

在这里插入图片描述
其中有三条路径, border为最外层的白色圆环,solid为填充绿色区域, center为最中心的白色√
这三条路径里面,除去pathData是我们不能去修改的,其他都可以由我们开发自定义。

android:name 为当前path设置名称,后续代码里面通过该名称查找该path进行颜色修改
android:fillColor 为当前path的填充颜色,后续通过代码setFillColor(int Color)进行修改
android:strokeColor 为当前path的边框颜色,后续通过代码setStrokeColor(int Color)进行修改
还有诸如strokeAlpha、strokeWidth、fillAlpha,根据名字即可知晓其作用。

代码设置其色值,例子:

 VectorChildFinder selectedVector = new VectorChildFinder(context, R.drawable.vector_drawable_ico_selected, imageView);
 VectorDrawableCompat.VFullPath solid = selectedVector.findPathByName("solid");
 solid.setFillColor(iconColor);
 imageView.invalidate(); //重绘imageView

提出疑问:

如果一个svg图中有好些path都为相同的颜色,那么我们能不能将这些path命名为相同的名字,如果不能,那针对这种不同path动态设置相同颜色的情况,我们如何避免重复的findPathByName、setFillColor。除去findPathByName之外,还有一个findGroupByName方法,是否可以通过这个group找到办法?

猜你喜欢

转载自blog.csdn.net/qq_39734865/article/details/132204375
今日推荐