自定义View之kotlin绘制折线图实例教程
程序员文章站
2023-12-15 16:46:28
什么是kotlin
kotlin,它是jetbrains开发的基于jvm的面向对象的语言。2017年的时候被google推荐android的官方语言,同时androi...
什么是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点个赞啦
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。