什么是Kotlin
Kotlin,它是JetBrains开发的基于JVM的面向对象的语言。2017年的时候被Google推荐Android的官方语言,同时Android studio 3.0正式支持这门语言,在这个编译器上创建一个Kotlin项目,非常方便,甚至可以Java转为Kotlin。
引言
早上看到有个童鞋在群里面发牢骚,说这个自定义view怎么画,不太会,ok,正好我也没事,那我就花两个小时帮你搞定他吧,先看下他要的效果;
再来看下我实现的效果
实现过程
主要分为x轴和y轴,由效果图可以看出,x轴主要分为7份,y轴主要分为4份,这样划分就比较简单的知道每条线的位置,每个位置的位置了,绘制起来就很简单;
先绘制y轴的四条线和文字
文字有三个,放到一个list里面,然后我们均分高度,然后遍历文字集合,根绝不同的高度绘制文字和横线
看下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/** * 绘制边框线和边框文本 */ private fun drawBorderLineAndText(canvas: Canvas) { when { valueTextY.size > 0 -> { val averageHeight = mNeedDrawHeight / (valueTextY.size + 1 ) ( 1 ..valueTextY.size + 1 ).forEach { i -> val nowadayHeight = averageHeight * (valueTextY.size + 1 - i) canvas.drawLine(mBrokenLineLeft, nowadayHeight + mBrokenLineTop, mNeedDrawWidth, nowadayHeight + mBrokenLineTop, mBorderLinePaint) if (i < valueTextY.size + 1 ) { val fm = mTextPaint.fontMetrics val mTxtHeight = Math.ceil((fm.leading - fm.ascent).toDouble()).toInt() canvas.drawText(valueTextY[valueTextY.size - i].toString() + "万" , mBrokenLineLeft, nowadayHeight + mBrokenLineTop - averageHeight / 2 + mTxtHeight / 2 , mTextPaint) } } } } } |
然后绘制x轴的文字
由于文字有6个,我们分为七份,从第一份之后开始绘制:
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
private fun drawMonthText(canvas: Canvas) { when { valueOld.size > 0 -> { var month = defaultStartMonth for (i in 1 ..valueOld.size) { val averageWidth = (mNeedDrawWidth / (valueOld.size + 1 )).toInt() val fm = mTextPaint.fontMetrics val mTxtHeight = Math.ceil((fm.leading - fm.ascent).toDouble()).toInt() canvas.drawText(month.toString() + "月" , (averageWidth * i).toFloat(), mNeedDrawHeight - mTxtHeight / 2 , mTextPaint) month++ } } } } |
最后绘制折线和折现上面的小球
这里我们需要把数据放进两个集合传入,然后根据数据算出每个点的坐标,最后根据path把每个点连接起来就ok了;
代码如下:
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
|
/** * 设置点的值 */ fun setPointValues(valueNew: ArrayList<Int>, valueOld: ArrayList<Int>) { this .valueNew = valueNew this .valueOld = valueOld } /** * 根据值计算在该值的 x,y坐标 */ fun getPoints(list: ArrayList<Int>): ArrayList<Point> { val avaregwidth = mNeedDrawWidth / (list.size + 1 ) val points = ArrayList<Point>(list.size) list.indices.forEach { i -> val valueY = list[i].toFloat() val averaHeight = (mNeedDrawHeight * 3 / 4 / maxValue).toDouble() val drawHeight = mNeedDrawHeight * 3 / 4 - (valueY * averaHeight).toFloat() + mBrokenLineTop val pointY = drawHeight.toInt() val pointX = ((avaregwidth * (i + 1 )).toInt() + mBrokenLineLeft).toInt() val point = Point(pointX, pointY) points.add(point) } return points } /** * 根据值绘制折线 */ private fun drawBrokenLine(canvas: Canvas) { when { valueOld.size > 0 && valueNew.size > 0 -> { val mPathOld = Path() val mPathNew = Path() val mPathOldshadow = Path() val mPathNewshadow = Path() val pointsOld = getPoints(valueOld) val pointsNew = getPoints(valueNew) for (i in 0 until mAnimatorValue) { val pointOld = pointsOld[i] val pointNew = pointsNew[i] if (i == 0 ) { mPathOld.moveTo(pointOld.x.toFloat(), pointOld.y.toFloat()) mPathNew.moveTo(pointNew.x.toFloat(), pointNew.y.toFloat()) mPathOldshadow.moveTo(pointOld.x.toFloat(), pointOld.y.toFloat()) mPathNewshadow.moveTo(pointNew.x.toFloat(), pointNew.y.toFloat()) } else { mPathOld.lineTo(pointOld.x.toFloat(), pointOld.y.toFloat()) mPathNew.lineTo(pointNew.x.toFloat(), pointNew.y.toFloat()) mPathOldshadow.lineTo(pointOld.x.toFloat(), pointOld.y.toFloat()) mPathNewshadow.lineTo(pointNew.x.toFloat(), pointNew.y.toFloat()) } } mBrokenLinePaint.color = Color.parseColor( "#ff5400" ) canvas.drawPath(mPathOld, mBrokenLinePaint) mBrokenLinePaint.color = Color.parseColor( "#ffff00" ) canvas.drawPath(mPathNew, mBrokenLinePaint) } } } /** * 绘制线上的圆 */ private fun drawLineCircle(canvas: Canvas) { when { valueOld.size > 0 && valueNew.size > 0 -> { val pointsOld = getPoints(valueOld) val pointsNew = getPoints(valueNew) for (i in 0 until mAnimatorValue) { val pointOld = pointsOld[i] val pointNew = pointsNew[i] mCirclePaint.color = Color.parseColor( "#ff5400" ) canvas.drawCircle(pointOld.x.toFloat(), pointOld.y.toFloat(), radius, mCirclePaint) mCirclePaint.color = Color.parseColor( "#ffff00" ) canvas.drawCircle(pointNew.x.toFloat(), pointNew.y.toFloat(), radius, mCirclePaint) } } } } |
最后就是添加动画了,可有可无,看需求吧
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
private fun initAnimator( size:Int) { valueAnimator = ValueAnimator.ofInt( 0 , size).setDuration(defaultDuration.toLong()) mUpdateListener = ValueAnimator.AnimatorUpdateListener { animation -> mAnimatorValue = animation.animatedValue as Int invalidate() } valueAnimator.addUpdateListener(mUpdateListener) valueAnimator.start() } fun setPointValues(valueNew: ArrayList<Int>, valueOld: ArrayList<Int>) { this .valueNew = valueNew this .valueOld = valueOld initAnimator(valueNew.size) } |
这样大体效果就已经实现了,最后加阴影,就更简单了,就直接给画笔设置阴影就行了
喜欢请到github点个赞啦
地址:github (本地下载)
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:https://www.jianshu.com/p/574234407eb1