Several ways to change picture color on Android

1. Application scenarios for changing picture color

Generally speaking, the same icon will be displayed in different colors on different pages and in different scenarios. Or different themes, using different colors, of course we can let the UI cut a picture for each color, but on the one hand the work is extremely tedious, on the other hand the application scenario is narrow and not conducive to expansion, every time there is a new design or new theme A new package needs to be released every time. In the end, the package size will also increase greatly, so it is necessary to dynamically change the color of the same icon through code.

In this article, we mainly talk about changing the color of icons and modifying a picture when the entire image is in the same color value. Of course, if some areas of the icon itself are transparent, the transparency will continue and will not be changed. Therefore, if the icon is a picture with a large area that is fully opaque, then the following solution does not apply, because after use, it will be a solid color block with an outline of the picture.
If you are drawing a shape type drawable for yourself, you can also dynamically set its color value through code.
If the image is svg, we can also set different colors for different areas (path or group). This requires us to have a certain understanding of the xml file of the svg image. We cannot directly set the color value like the png type.

2. Scheme for updating icon color

2.1 Directly modify the icon color through xml

The first method is to set tint to src. Here you need to pay attention to the fact that tint needs to use the app tag because of version compatibility.

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

The second method is to set backgroundTint to the background.

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

The third method can set foreground and foregroundTint for applications that are at least compatible with Android version 23.

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

Note :

  1. Since foreground is the foreground, imageview will not get its width and height and set it to its own width and height, so when using foreground, you must either fix the width and height, or set src or background. The third option is not recommended to modify the icon color.
  2. When setting tint, you can set the corresponding tintMode according to your own needs. Different modes have different color modification methods for pictures. If you just change the icon to another color, just use the default without setting it. Can

2.2 Dynamically set the local drawing shape type drawable

Generally speaking, locally drawn shapes are set to the background, so we can make the following settings:

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)) 

Note:

  1. Due to the cache of the Android system, after the resource drawable is generated, the object will be called directly when using the resource. If we dynamically adjust the color of the resource in the code without setting mutate(), then the subsequent call to the resource will The color values ​​are all dynamically set colors. But if we set mutate(), it means that this modification will not be cached. In the same way, as long as we dynamically update the color of the drawable, we must consider the call of this method.
  2. For the fill color settings, you need to pay attention to the solid color settings and gradient color settings, which are color and colors respectively. The corresponding parameters are @ColorInt int color and @ColorInt int[] colors respectively.

2.3 Code to dynamically set image color

The first method is to set colorfilter to imageview

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

The second method is to set imageTintList to imageview.

imageview.imageTintList = ColorStateList.valueOf(colorInt)

Same as xml, you can also set backgroundTintList = ColorStateList.valueOf(colorInt)
here . If some control icons are buttons (CheckBox), you can use buttonTintList = iconsColorStates
for the drawable of textview :

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

Note:
Regarding ColorStateList, if it is just a certain color, you can directly use ColorStateList.valueOf(colorInt). If you want to set different colors for different states, you can use ColorStateList(int[][] states, @ColorInt int[ ] colors) to set.
For example:
ColorStateList(arrayOf(intArrayOf(-android.R.attr.state_checked),intArrayOf(android.R.attr.state_checked)), intArrayOf(iconRgb, iconSelectRgb))

Expand it

ColorStateList can set colors in different states, so are there different icons used in different states? Of course there is: StateListDrawable, which is used similar to ColorStateList, for example:

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

Of course, the drawable used in the above different states can also use the methods listed above to dynamically set the color.

2.4 Dynamic color modification of svg images

There is such a svg picture, the xml is as follows

<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>

Insert image description here
There are three paths, border is the outermost white ring, solid is the filled green area, and center is the center white √
Among these three paths, except for pathData, we cannot modify it. The others can be developed and customized by us. .

android:name sets the name for the current path. In the subsequent code, the path is searched for by this name and the color is modified.
android:fillColor is the fill color of the current path. Subsequent modifications are made through the code setFillColor(int Color).
android:strokeColor is the border color of the current path. , and then modify it through the code setStrokeColor(int Color).
There are also other functions such as strokeAlpha, strokeWidth, and fillAlpha. You can know their functions according to their names.

The code sets its color value, example:

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

ask a question:

If there are many paths in an svg image with the same color, can we name these paths with the same name? If not, how can we avoid repeated findPathByName, setFillColor. In addition to findPathByName , there is also a findGroupByName method. Is it possible to find a way through this group?

Guess you like

Origin blog.csdn.net/qq_39734865/article/details/132204375