Gtihub传送门 |
---|
目录
Canvas的高级使用
在我的
Github
开源库中,今天刚写好了一个饼图的绘制,这里主要就是对饼图绘制的一个讲解了。
之前我们讲过了一个Path
,但是如果全用Path
去实现,也不是说不能够实现,但是并不适用于很多的场景情况。
这里的话,我们主要讲的就是关于Canvas
的使用了。之前我们在Path
中用到过这样的一个函数moveTo
,也就是把路径从当前的位置移动到新的坐标上。那我们的Canvas
是否有这样的功能呢?
自然是有的了,这里直接作出一个解答,他的函数就是translate
,但是有一点要注意!!!这个函数是一个相对移动,而不是绝对移动。
canvas?.translate(60f, 80f)
paint?.let { canvas?.drawCircle(0f, 0f, 100f, it) }
canvas?.translate(60f, 80f)paint?.color = Color.BLUE
paint?.let { canvas?.drawCircle(0f, 0f, 100f, it) }
上述就是实现代码以及一个贴图了。你可以直观的感受到这个移动其实是基于当前的基础来完成的。但是读者会说了,这种效果完全可以让我通过Path
来完成啊,没必要通过Canvas
,ok,确实可以,你也可以通过Path
来实现。
但是难点现在才来,下图的样式该怎么实现??
在知道怎么写代码之前,那我们要知道肯定是他的组成成分到底是什么了。
- 两条线的组合。从直观上就可以看出,这个折线应该是两条直线进行组合
- 两行文字的组合。也就是图片中的描述四和6.0%
如果让我们直接去获取绝对坐标,然后进行绘制,那是不是会非常麻烦呢?所以这里要引入一个Canavs
的操作方法。
Canvas
操作
在使用之前需要注意,画布是需要保存的,不然画布将不断的保留上一次的状态进行绘制,那整体就会呈现一种叠加混乱的局面。而这个方法就是save()
和restore()
的成对使用。
for (i in 0..2) {
canvas?.save()
paint?.color = Color.BLUE
canvas?.translate(60f, 80f)
canvas?.scale(0.5f, 0.5f)
paint?.let { canvas?.drawCircle(0f, 0f, 100f, it) }
canvas?.restore()
}
使用前 | 使用后 |
---|---|
你可以把这个操作理解为画布归位,或者说画布重置。而这个重置对应的就是保存了save()
之前的操作过程。
Scale
这个效果不再赘述了。
Rotate
和其他的都是一样的会有两种画布的操作函数
- rotate(float degrees, float px, float py),就是自定义旋转圆心
- rotate(float degrees),画布当前位置作为旋转圆心
canvas?.save()
paint?.color = Color.BLUE
canvas?.translate(60f, 80f)
canvas?.rotate(45f)
// 以自身中心作为圆点旋转
// canvas?.rotate(45f,30f, 40f)
paint?.let { canvas?.drawRect(0f, 0f, 100f, 100f, it) }
canvas?.restore()
饼图的实现其实就是基于这个函数来完成的。
Shew
和其他的不同了,他并不再通过我们的坐标圆心,而是对标我们X
和Y
轴
canvas?.save()
paint?.color = Color.BLUE
canvas?.translate(60f, 80f)
canvas?.skew(0f, 1f)
paint?.let { canvas?.drawRect(0f, 0f, 100f, 100f, it) }
canvas?.restore()
传入的数据其实就是分别与X
和Y
轴的正切值,通过截图工具,你能够明显的发现这个问题。画了绿色框框的部分,你可以看到的是正好一个45度的大小。
通过画图你也可以这样理解,就是Y
轴顺时针方向旋转45度。
饼图绘制的基本思路
上面讲过了画布的一些基本操作,那我们要具体讲一下这个饼图我们该怎么绘制了。讲实话,我代码里已经基本注释了,所以具体的以代码为准,这里只做简单的讲解。几个考虑部分:- 圆和文字怎么兼容,这是一个重难点,我也只能说通过多次尝试,到圆为0.3倍的宽度最为合适了。因为0.5倍,正好占满;0.4倍,文字太小。这个值你可以自行做一个修改处理。
- 上面说过的介绍线怎么画。文字的的布局肯定直接根据介绍线来变动了,那这个介绍线就是至关重要的一点了。
- 弧形的颜色怎么变换。
基本就是以上问题,问题1我已经做出来回答,后续两个问题将一个个作出解释。
介绍线怎么画
在我的代码中,其实分为两块,一是圆弧,一是介绍,这也是他们的绘制顺序了。但是需要考虑一个问题:介绍线的位置确定?
这个问题你需要看一下我的图例了,你有没有注意到,我的介绍线,好像都是关于单个圆弧居中的呢?
那我们的方案其实就来了,上面我们讲到过了什么?Rotate
还记得这个函数嘛!!通过数据运算,有了每个圆弧的大小,那我们还不能去进行绘制嘛?不就是先划线,再旋转吗。然后旋转就是这样的一个公式要去计算。
// 旋转角度 = 前面的弧度 + 当前弧度的一半
private fun getRatioSum(j: Int): Float {
var sum = 0f
for (i in 0 until j) {
sum += mRatios!![i]
}
return sum
}
private fun getRatioHalfSumDegrees(j: Int): Float {
var sum = getRatioSum(j)
sum += mRatios!![j] / 2
return sum * 360
}
弧形的颜色怎么变换
跟前面的圆弧一样,但是是一个个圆弧来组成圆,那这个时候,就是要知道前面的弧度,然后对当前的弧度的计算,也就是扫过的区间进行计算了。
private fun drawArc(canvas: Canvas) {
val drawArc = 360 * scale
for (i in mRatios!!.indices) {
mArcPaint?.color = mArcColors!![i]
mArcPaint?.let {
canvas.drawArc(
arcRect!!,
getRatioSum(i) * drawArc,
mRatios!![i] * drawArc,
true,
it
)
}
}
}
基本上就是靠上述的两个来完成的,是不是还是比较简单的呢。冲冲冲,Demo
抄起来,你就有一份自己的饼图绘制了。