绘制SimpleProgressBar

继承 View 实现 ProgressBar, 练习使用 Kotlin

参考 https://github.com/lingochamp/MagicProgressWidget

一些方法说明:

canvas clipRect

canvas.clipRect(RectF rect)
canvas.clipRect(RectF rect, Region.Op op)

裁剪画布,设置画布的显示区域,调用 clipRect 之后,只会显示被裁剪的区域,之外的区域不会显示。只对clipRect 之后的绘制操作有效

paint.isAntiAlias = true
paint.color = Color.BLACK
paint.textSize = 30.0F

canvas.clipRect(100F, 100F, 350F, 600F, Region.Op.INTERSECT);
canvas.drawColor(Color.RED);
canvas.drawCircle(100F, 100F, 100F, paint);

裁剪参数:

  • DIFFERENCE是第一次不同于第二次的部分显示出来
  • REPLACE是显示第二次的
  • REVERSE_DIFFERENCE 是第二次不同于第一次的部分显示
  • INTERSECT交集显示(默认)
  • UNION全部显示
  • XOR补集 就是全集的减去交集剩余部分显示

交集显示

canvas save

canvas.save()
canvas.restore()

save() 用来保存 canvas 的状态,restore() 用来恢复 canvassave() 时的状态。例如对画布进行了旋转、缩放操作之后,画布坐标就变了,然后想继续使用正常的画布坐标,就可以使用: save() -> 操作 -> restore() -> 继续操作。

绘制 SimpleProgressBar

class SimpleProgressBar : View {
    constructor(context: Context) : super(context)
    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
    constructor(context: Context, attributeSet: AttributeSet, defaultAttr: Int) : super(context, attributeSet, defaultAttr)

    private var mAnimator: ValueAnimator? = null
    private var currentPresent = 0F
    private lateinit var mRectF: RectF
    private val backPaint = Paint()
    private val fillPaint = Paint()
    private var backColor = Color.GRAY
        set(value) {
            field = value
            invalidate()
        }
    private var fillColor = Color.RED
        set(value) {
            field = value
            invalidate()
        }

    init {
        backPaint.color = backColor
        backPaint.isAntiAlias = true
        backPaint.style = Paint.Style.FILL

        fillPaint.color = fillColor
        fillPaint.isAntiAlias = true
        fillPaint.style = Paint.Style.FILL
        setPercent(0.6F)
    }

    fun setPercent(percent: Float, duration: Long = 2000L) {
        mAnimator?.cancel()
        mAnimator = ValueAnimator.ofFloat(currentPresent, percent)
        mAnimator?.duration = duration
        mAnimator?.addUpdateListener({
            currentPresent = it.animatedValue as Float
            invalidate()
        })
        mAnimator?.start()
    }

    private var mWidth: Int = 0
    private var mHeight: Int = 0
    private var radius: Float = 0F

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        mRectF = RectF(
                paddingLeft.toFloat(),
                paddingTop.toFloat(),
                (w - paddingRight).toFloat(),
                (h - paddingBottom).toFloat())
        mWidth = w - paddingLeft - paddingRight
        mHeight = h - paddingTop - paddingBottom
        radius = mHeight / 2F
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        //draw background rect
        canvas.save()
        mRectF.right = mWidth.toFloat()
        canvas.drawRoundRect(mRectF, radius, radius, backPaint)
        //draw fill progress
        val fillWidth = mWidth * currentPresent
        when {
            fillWidth > 0F && fillWidth < radius * 2 -> {
                mRectF.right = fillWidth
                canvas.clipRect(mRectF)
                mRectF.right = radius * 2
                canvas.drawRoundRect(mRectF, radius, radius, fillPaint)
            }
            fillWidth > radius -> {
                mRectF.right = fillWidth
                canvas.drawRoundRect(mRectF, radius, radius, fillPaint)
            }
        }
        canvas.restore()
    }
}