分段进度条&分段图标抖动动画的实现

分段进度条&分段图标抖动动画的实现

先上图,https://github.com/Warkey1991/Jackview觉得有用的话,希望给个star


 该自定义View有三个问题需要一一实现

1. **如何实现分段** ,

2. **如何用canvas 实现抖动的动画效果**

3. **如何识别点击区域的点击事件**

 以下就针对三个问题提供解决思路和实战代码

a.本例中采用的是均分三段,定义一个数组A = {3,5,8},再将每一段根据A 中的A[i]的值均分,

如图


绘制进度的时候,需要先找出当前进度progress 所在的区间,然后分段绘制。具体代码如下:

```kotlin

//查找所在区间的索引

private fun findRange(): Int {

    if (progress >= segments.last().progress) {

        progressPadding = 0

        return segments.size - 1

    }

    var index = 0

    for (i in 0 until segments.size - 1) {

        if (progress in segments[i].progress..segments[i + 1].progress) {

            index = i + 1

        }

    }

    if (index >= 1) {

        currentSegmentProgress = progress - segments[index - 1].progress

    }

    return index

}

//绘制

  override fun onDraw(canvas: Canvas?) {

        super.onDraw(canvas)

        rect.set(0f, (height / 2 - dip2px(5f)).toFloat(), width.toFloat(), (height / 2 + dip2px(5f)).toFloat())

        canvas?.drawRoundRect(rect, horizontalRound, horizontalRound, bgPaint)

        val index = findRange()

        var eachWidth = (width - lightBitmap.width) / segments.size

        if (index == segments.size - 1) {

            eachWidth = width / segments.size

        }

        //转为float,可以预防divide by zero 的异常

        val smallEachWidth = eachWidth.toFloat() / segmentMaxs[index].toFloat()

        var x = eachWidth * index + smallEachWidth * currentSegmentProgress

        x = x.coerceAtMost(width.toFloat())

        rect.right = x

        canvas?.drawRoundRect(rect, horizontalRound, horizontalRound, progressPaint)

        drawBitmaps(canvas)

    }

```

b.用canvas 实现抖动的动画效果:

  分析了单独的View用rotate 动画实现的方式,可以得出结论,只需要每次绘制的时候旋转canvas画布即可,每次旋转的弧度需要自己自行定义,本例中使用的是`listOf(-5.0f, -4f, -3f, -2f, -1f, 2f, 3f, 4f, 5f,

            -5.0f, -4f, -3f, -2f, -1f, 2f, 3f, 4f, 5f,

            -5.0f, -4f, -3f, -2f, -1f, 2f, 3f, 4f, 5f,

            0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f,

            0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f,

            0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f)`

抖动三次停顿一会的效果,定义一个数组的索引index = 0, 从0 开始,开启一个线程,每16ms,index+1,重新绘制即可实现,

代码如下:

```kotlin

private fun rotate() {

        thread {

            while (!needStopThread) {

                if (animCount == rotateAngle.size) {

                    animCount = 0

                }

                Thread.sleep(16)

                post {

                    invalidate()

                }

                animCount++

            }

        }

    }

```

绘制核心代码:

```kotlin

//获取旋转的弧度

val degrees = rotateAngle[animCount % rotateAngle.size]

canvas?.save()

//以中心点旋转

canvas?.rotate(degrees, rectF.centerX(), rectF.centerY())

canvas?.drawBitmap(imageBitmap, null, innerRectF, null)

canvas?.restore()

```

c. 添加点击区域的点击事件:

三个红色节点的坐标位置在绘制的时候需要保存起来`    private var touchCallBackRectF = mutableListOf()`,定义一个变量用于保存节点的区域位置信息。

复写onTouchEvent 方法,在MotionEvent.ACTION_UP 中判断该点击的位置是否在touchCallBackRectF 中,找出对应的位置。

```kotlin

@SuppressLint("ClickableViewAccessibility")

    override fun onTouchEvent(event: MotionEvent?): Boolean {

        when (event?.action) {

            MotionEvent.ACTION_UP -> {

                val x = event.x

                val y = event.y

                for (i in 0 until touchCallBackRectF.size) {

                    if (touchCallBackRectF[i].contains(x, y)) {

                        segments[i].status = BoxStatus.AVAILABLE.ordinal

                        Toast.makeText(context, "click index:${i}", Toast.LENGTH_SHORT).show()

                    }

                }

            }

        }

        return true

    }

```

你可能感兴趣的:(分段进度条&分段图标抖动动画的实现)