默认顺时针画出来的。 每多画一个扇形,起始角度都要加起前面几个扇形的角度,划过的角度视扇形大小而定。
画扇形
直接写法
paint.color = resources.getColor(R.color.light_green, null)
canvas.drawArc(width / 2f - RADIUS, height / 2f - RADIUS, width / 2f + RADIUS, height / 2f + RADIUS,
0f, 60f,
true, paint)
paint.color = resources.getColor(R.color.yellow, null)
canvas.drawArc(width / 2f - RADIUS, height / 2f - RADIUS, width / 2f + RADIUS, height / 2f + RADIUS,
60f, 60f,
true, paint)
paint.color = resources.getColor(R.color.pink, null)
canvas.drawArc(width / 2f - RADIUS, height / 2f - RADIUS, width / 2f + RADIUS, height / 2f + RADIUS,
120f, 90f,
true, paint)
paint.color = resources.getColor(R.color.lime, null)
canvas.drawArc(width / 2f - RADIUS, height / 2f - RADIUS, width / 2f + RADIUS, height / 2f + RADIUS,
210f, 115f,
true, paint)
paint.color = resources.getColor(R.color.purple, null)
canvas.drawArc(width / 2f - RADIUS, height / 2f - RADIUS, width / 2f + RADIUS, height / 2f + RADIUS,
325f, 45f,
true, paint)
for循环
class PieView(context: Context?) : View(context) {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
private val path = Path()
private var colors: IntArray = intArrayOf(R.color.yellow, R.color.purple100, R.color.pink, R.color.lime, R.color.red100)
private var angles: FloatArray = floatArrayOf(60f, 60f, 90f, 105f, 45f)
private var startAngle = 0f
private var sweepAngle = 0f
override fun onDraw(canvas: Canvas) {
for ((index, item) in colors.withIndex()) {
paint.color = resources.getColor(item, null)
sweepAngle = angles[index]
canvas.drawArc(width / 2f - RADIUS, height / 2f - RADIUS, width / 2f + RADIUS, height / 2f + RADIUS,
startAngle, sweepAngle, true, paint)
startAngle += sweepAngle
}
}
}
扇形推出
要点1. canvas 的保存与恢复
// 在推出一开始一定要执行
canvas.save()
// 在最后一定要恢复状态
canvas.restore()
要点2. 开始角度要叠加
startAngle += sweepAngle
要点3. 三角函数角度计算
// 一定要与 startAngle 相加
theta = Math.toRadians((startAngle + sweepAngle / 2).toDouble()).toFloat()
// x, y 值计算
x = offset * cos(theta)
y = offset * sin(theta
要点4. 推出用 canvas.translate
// 要在执行画扇形方法前设置偏移
canvas.translate(offset * cos(theta), offset * sin(theta))
完整代码
class PieView(context: Context?) : View(context) {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
private val path = Path()
private var colors: IntArray = intArrayOf(R.color.yellow, R.color.purple100, R.color.pink, R.color.lime, R.color.red100)
private var angles: FloatArray = floatArrayOf(60f, 60f, 90f, 105f, 45f)
private var startAngle = 0f
private var sweepAngle = 0f
private var offset = 30f.px // 自定义扇形推出的偏移量,也就是三角形斜边
private var theta = 0f // 三角形角度, offset 与 x轴的夹角
private var indicator = 2 // 自定义哪个扇形推出
override fun onDraw(canvas: Canvas) {
for ((index, item) in colors.withIndex()) {
paint.color = resources.getColor(item, null)
sweepAngle = angles[index]
if (index == indicator) {
canvas.save()
theta = Math.toRadians((startAngle + sweepAngle / 2).toDouble()).toFloat()
canvas.translate(offset * cos(theta), offset * sin(theta))
canvas.drawArc(width / 2f - RADIUS, height / 2f - RADIUS, width / 2f + RADIUS, height / 2f + RADIUS,
startAngle, sweepAngle, true, paint)
} else {
canvas.drawArc(width / 2f - RADIUS, height / 2f - RADIUS, width / 2f + RADIUS, height / 2f + RADIUS,
startAngle, sweepAngle, true, paint)
}
if (index == indicator) canvas.restore()
startAngle += sweepAngle
}
}
}
总结
饼图 和 [[1.b 仪表盘绘制]] 的计算方式有相似之处,即都是利用三角函数正余弦来计算偏移的x,y值。