android 自定义还原色彩图控件 ProgressImageView

1,218 阅读2分钟

android 自定义还原色进度imageView

先上个效果图

首先底图是灰色,然后根据进度还原色彩图像。现有的imageView 就非常适合进行改造了。

  • 继承imageView
  • 给imageView设置ColorFilter让底图变灰
  • 重写onDraw方法,设置canvas裁剪区域,绘制色彩图
class ProgressImageView(context: Context?, attrs: AttributeSet?, defStyleAttr: Int)
    : AppCompatImageView(context, attrs, defStyleAttr) {


    constructor(context: Context?): this(context, null, 0)

    constructor(context: Context?, attrs: AttributeSet?): this(context, attrs, 0)


    private var pWidth = 0
    private var pHeight = 0

    private var pDrawable: Drawable ? = null
    private var progress: Float = 0f


    init {
    	//设置图片饱和度为0就能显示黑白图片
        val cm = ColorMatrix()
        cm.setSaturation(0f)
        val cmf = ColorMatrixColorFilter(cm)
        colorFilter = cmf
    }


    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        if(pDrawable != null && canvas != null && progress != 0f){
            canvas.save()

            if (imageMatrix != null) {
                canvas.concat(imageMatrix)
            }
			//设置裁剪区域
            canvas.clipRect(createClipRect())
            //绘制原色彩图在底图之上
            pDrawable!!.draw(canvas)

            canvas.restore()
        }
    }


    override fun setImageDrawable(drawable: Drawable?) {
        super.setImageDrawable(drawable)
        if(pDrawable != drawable && drawable != null){
        	//这里要注意必须调用mutate()这个方法
            pDrawable = drawable.constantState?.newDrawable()?.mutate()
            configBound()
        }
    }


    //创建显示原图的区域
    private fun createClipRect(): Rect {
        val height = pHeight * (progress / 100f)
        val rect = Rect(0, 0, pWidth, height.toInt())
        return rect
    }


    private fun configBound(){
        pDrawable?.apply {
            this.clearColorFilter()
            pWidth = this.minimumWidth
            pHeight = this.minimumHeight
            this.setBounds(0, 0, pWidth, pHeight)
        }
    }


    fun setProgress(progress: Float){
        //防止多次设置
        if(progress < this.progress){
            return
        }

        this.progress = progress
        if(this.progress > 100f){
            this.progress = 100f
        }
        invalidate()
    }
}

为了让两张图片重叠一致,可以直接复用imageView的Matrix,这样两张图片的缩放模式能够保持一致性。

给imageView设置ColorFilter让底图变灰

重写setImageDrawable方法,在这里进行色彩图drawable的创建

drawable.constantState?.newDrawable()?.mutate()

可以利用constantState创建新的drawable,这里要注意一下,此时虽然是两个drawable,但是两个drawable是共享同一个constantState的,这也就意味着两个drawable使用的同一个ColorFilter如果调用clearColorFilter(),那么灰色的底图也会被还原成原来的色彩图,所以需要在newDrawable() 后面调用 mutate(),这样就不会共享资源了。

设置canvas裁剪区域,绘制色彩图

在绘制彩色图的时候,利用canvas中的clipRect() 方法绘制进度部分区域的图片

代码比较简单,直接贴源码了