绘制SimpleProgressBar

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

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

一些方法说明:

canvas clipRect

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

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

1
2
3
4
5
6
7
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

1
2
canvas.save()
canvas.restore()

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

绘制 SimpleProgressBar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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()
}
}
赏杯咖啡 🍵 Donate