自定义View之kotlin绘制折线图二

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/villa_mou/article/details/82783034

引言

早上看到有个童鞋在群里面发牢骚,说这个自定义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

欢迎大家扫描关注作者公众号,长期推送Android技术干货,感谢大家支持:


在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/villa_mou/article/details/82783034