GradientDrawable的使用,和简单源码分析

Posted 夜尽天明89

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GradientDrawable的使用,和简单源码分析相关的知识,希望对你有一定的参考价值。

gradient:英 [ˈgreidjənt] 美 [ˈgredɪənt] 倾斜度,坡度,变化率
从字面意思理解,是一个可以变化颜色、有渐变效果的Drawable

GradientDrawable extends Drawable

来个效果图和对应的代码。并不复杂

对应代码(布局我就不写了,没有任何特别的)

 		//圆角矩形。TextView
        rounded_rectangle.apply 

            var gradientDrawable: GradientDrawable = GradientDrawable()

            Log.e("000 = call back ","$gradientDrawable.callback")

            gradientDrawable.setColor(Color.GREEN)

            Log.e("111 = call back ","$gradientDrawable.callback")

            gradientDrawable.cornerRadius = dp2Px(20f)

            Log.e("222 = call back ","$gradientDrawable.callback")

            background = gradientDrawable

            Log.e("333 = call back ","$gradientDrawable.callback")

        

        //圆角矩形,设置4个角不同的度数。TextView
        rounded_rectangle_radius.apply 

            var gradientDrawable: GradientDrawable = GradientDrawable()
            gradientDrawable.setColor(Color.GREEN)
            gradientDrawable.setCornerRadii(
                floatArrayOf(
                    dp2Px(10f),
                    dp2Px(10f),
                    dp2Px(15f),
                    dp2Px(15f),
                    dp2Px(20f),
                    dp2Px(20f),
                    dp2Px(25f),
                    dp2Px(25f)
                )
            )

            background = gradientDrawable

        

        //圆角矩形,带边线。TextView
        rounded_rectangle_stroke.apply 

            var gradientDrawable: GradientDrawable = GradientDrawable()
            gradientDrawable.setColor(Color.GREEN)
            gradientDrawable.cornerRadius = dp2Px(20f)
            gradientDrawable.setStroke(dp2Px(2f).toInt(), Color.RED)

            background = gradientDrawable

        

        //水平线。view
        h_line.apply 

            var gradientDrawable: GradientDrawable = GradientDrawable()

            gradientDrawable.setShape(GradientDrawable.LINE);
            gradientDrawable.setStroke(2, Color.RED);

            background = gradientDrawable

        

        //水平虚线。view
        h_xu_line.apply 

            var gradientDrawable: GradientDrawable = GradientDrawable()

            gradientDrawable.setShape(GradientDrawable.LINE);
            gradientDrawable.setStroke(2, Color.RED, 10f, 30f);

            background = gradientDrawable

        

        //圆形控件。TextView
        circle_view.apply 

            var gradientDrawable: GradientDrawable = GradientDrawable()

            gradientDrawable.setColor(Color.GREEN);
            gradientDrawable.setShape(GradientDrawable.OVAL);

            background = gradientDrawable

        

        //圆形控件,渐变背景。TextView
        circle_view_2.apply 

            var gradientDrawable: GradientDrawable = GradientDrawable()

            gradientDrawable.setShape(GradientDrawable.OVAL)

            //设置描边
            gradientDrawable.setStroke(dp2Px(2f).toInt(), Color.RED)

            //设置线性渐变,除此之外还有:GradientDrawable.SWEEP_GRADIENT(扫描式渐变),GradientDrawable.RADIAL_GRADIENT(圆形渐变)
            gradientDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT)

            gradientDrawable.setOrientation(GradientDrawable.Orientation.RIGHT_LEFT) //设置渐变方向

            gradientDrawable.setColors(
                intArrayOf(
                    Color.RED,
                    Color.GREEN,
                    Color.BLUE
                )
            ) //增加渐变效果需要使用setColors方法来设置颜色(中间可以增加多个颜色值)

//            gradientDrawable.alpha = 70 //设置透明度

            background = gradientDrawable

        

接下来,简单分析下这个的源码。

var gradientDrawable: GradientDrawable = GradientDrawable()
gradientDrawable.XXX(...)

任何一个方法进去,都会调用

invalidateSelf()

去看 invalidateSelf ,会进入Drawable

    public void invalidateSelf() 
        final Callback callback = getCallback();
        if (callback != null) 
            callback.invalidateDrawable(this);
        
    

这个callback,是Drawable下的,全部方法如下

public interface Callback 
	
	void invalidateDrawable(@NonNull Drawable who);

	void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when);

	void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what);


也就是说,在使用 GradientDrawable 的时候,每次设置属性,都会进行2步操作:1、获取回调接口;2、如果回调不为空,就调用 invalidateDrawable 去绘制。

什么时候 回调 不为空呢?也就是,什么时候,会去绘制呢?我上面代码里加了Log,看下日志

E/000 = call back: null
E/111 = call back: null
E/222 = call back: null
E/333 = call back: androidx.appcompat.widget.AppCompatTextViewee92a86 V.ED..... ......I. 0,0-0,0 #7f070082 app:id/rounded_rectangle

看来,是TextView设置了 background 后,才进行了背景的绘制。

去看下 TextView 的 setBackground

public void setBackground(Drawable background) 
        //noinspection deprecation
        setBackgroundDrawable(background);


public void setBackgroundDrawable(Drawable background) 
	......
	if (background != null) 
		......
		// Set callback last, since the view may still be initializing.
		background.setCallback(this);
		......
	
	......


总结下:GradientDrawable 设置各种属性的时候,因为callback 为空,不会进行绘制(不会造成浪费)。在最后设置 setBackground 时,传入了 background ,且设置了 callback ,在后续代码中,触发了绘制

以上是关于GradientDrawable的使用,和简单源码分析的主要内容,如果未能解决你的问题,请参考以下文章

GradientDrawable 获取单一颜色

GradientDrawable 获取单一颜色

GradientDrawable 获取单一颜色

GradientDrawable 获取单一颜色

改变的 GradientDrawable 在不同的地方被不必要地重复使用

在代码中设置形状资源 / GradientDrawable 的填充