实战酷毙了的自定义View(三)

1,879 阅读4分钟

Gtihub传送门

前言

在之前我们讲到过了PaintCanvas的一些用法,但是其实还不能解决全部问题,在我们的项目中你是不是有需要这样的东西——滑动和动画。对!!如何实现像RecyclerView的滑动效果,和一个动画效果,接下来我们将会讲到。

目录

  1. 实战酷毙了的自定义View(一)
  2. 实战酷毙了的自定义View(二)
  3. 实战酷毙了的自定义View(三)

滑动

其实为了寻求方便,直接使用的是Android已经封装好的类GestureDetector。内部存在一个简单的手势分辨的内部类SimpleOnGestureListener,我们可以直接调用然后完成滑动这个动作。

private inner class BarGesture : SimpleOnGestureListener() {

        override fun onDown(e: MotionEvent?): Boolean {
            return true
        }

        override fun onScroll(
            e1: MotionEvent?,
            e2: MotionEvent?,
            distanceX: Float,
            distanceY: Float
        ): Boolean {
            if (mBarShowNum <= mMinBarScrollShowNum) return false

            val position = dp2px(context, scrollX.toFloat())
            if (distanceX >= 0) {
                if (position <= mBarMaxWidth) {
                    scrollBy(distanceX.toInt(), 0)
                }
            } else {
                if (distanceX >= -1 * position) {
                    scrollBy(distanceX.toInt(), 0)
                }
            }
            return false
        }
    }

为了滑动,自动会有一个距离的要求了,我们调用View已经定义好的ScrollBy,就可以进行挪移了。

总体来说,其实他已经给我们封装好了,要做的就是一个方向的判断。另外在代码中我们能看到scrollX这个变量,这是View已经定义好的一个变量,记住他等等有大用。

关于性能

在之前我们讲到过一个问题,就是Android的坐标系是怎样的。有所遗忘的读者们可以重温一下Android自定义View,你摸的透透的了?对于超出屏幕宽度的图案我们是否会进行绘制呢?

我们对整个绘制做一个测验好了,下面先给出测试代码

override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        // 1
        var count:Int = 0
        for (i in mData!!.indices) {
//            if (!checkIsNeedDraw(i)) {
                val height = (mMaxData - mData!![i]) / mMaxData * mBarMaxHeight
                mBarPaint?.shader = null
                drawBarValue(canvas, i, height)
                drawDescriptions(canvas, i)
                mBarPaint?.shader = shader
                drawBars(canvas, height)
                // 2
                count++
//            }
            if (i != mData!!.size - 1) {
                canvas?.translate(mBarSingleWidth, 0f)
            }
        }
        // 3
        Log.e("onDraw", count.toString())
    }

标注的代码在BarChartView类的源码中加一下就好了。我给出的数据量是7个,那看看结果给出是几次呢!!!

Oh my God!!!7次,真的是7次,我的天呐,那不就是说,我超出的部分你也要画????我要你有啥用啊,你别给我画呀。

算了算了,知道了要绘制,那我们就要找解决方案了。我们刚刚提及到了一个scrollX这个变量,其实就是记录我们当前屏幕最左边相对于坐标轴而言的,在坐标X轴的哪个位置了,而屏幕大小又是固定的,那我们就可以引申出这样的想法。

引申出的代码如下

private fun checkIsNeedDraw(i: Int): Boolean {
        if (mBarSingleWidth * (i + 1) < scrollX) return true
        if (mBarSingleWidth * i > scrollX + mWidth) return true
        return false
    }

看看加了他的效果把。

出现了6着数值,说明我们绘制的数量明显减少了不是。证明方法有效!!!!

动画

动画其实是一个很大的知识点了,这里不会仔细讲这个,一方面是因为他的知识容量大,一方面是我的接触的还不够全面。

private fun initAnimation() {
        animator = ValueAnimator.ofFloat(0.3f, 1f)
        // 通过插值器来完成动画
        animator?.interpolator = LinearInterpolator()
        animator?.duration = 1500
        animator?.addUpdateListener { animation ->
            scale = animation.animatedValue as Float
            postInvalidate()
        }
    }

先来看看我的代码好了。我们能看到一个LinearInterpolator()这样的玩意儿,定位一下他,就可以看到他的大家族成员有谁了。

通过动画时间的设定,和一个scale也就是值的改变,动态的更改数据,其实也就是不断重绘,来完成我们所能够看到的逐渐增长的效果。想想也应该没有这么困难了,你可以直接调用这些类,来完成一些简单的动画效果。

柱状图的绘制

重头戏,重头戏!!!

其实我们之前已经考虑了很多我在写柱状图的时候遇到的一些问题了,所以大致上的话还是以看源码为基准,这里主要展示的还是我的一个设计稿,因为你要去绘制一个柱状图的话,肯定是要有一定的计算的。

基本就是靠这个简陋的设计稿完成的我的这个类的了,有Bug请见谅。

不过也同样希望你能Star一下我的这个项目View_How_To_Make_It