自定义View之kotlin绘制折线图实例教程

什么是Kotlin

Kotlin,它是JetBrains开发的基于JVM的面向对象的语言。2017年的时候被Google推荐Android的官方语言,同时Android studio 3.0正式支持这门语言,在这个编译器上创建一个Kotlin项目,非常方便,甚至可以Java转为Kotlin。

引言

早上看到有个童鞋在群里面发牢骚,说这个自定义view怎么画,不太会,ok,正好我也没事,那我就花两个小时帮你搞定他吧,先看下他要的效果;

再来看下我实现的效果

实现过程

主要分为x轴和y轴,由效果图可以看出,x轴主要分为7份,y轴主要分为4份,这样划分就比较简单的知道每条线的位置,每个位置的位置了,绘制起来就很简单;

先绘制y轴的四条线和文字

文字有三个,放到一个list里面,然后我们均分高度,然后遍历文字集合,根绝不同的高度绘制文字和横线

看下代码:

/**

* 绘制边框线和边框文本

*/

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个,我们分为七份,从第一份之后开始绘制:

代码如下:

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了;

代码如下:

/**

* 设置点的值

*/

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)

}

}

}

}

最后就是添加动画了,可有可无,看需求吧

代码如下:

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 (本地下载)

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。

以上是 自定义View之kotlin绘制折线图实例教程 的全部内容, 来源链接: utcz.com/p/241216.html

回到顶部