码迷,mamicode.com
首页 > 其他好文 > 详细

Kotlin动态图

时间:2019-09-03 22:45:59      阅读:137      评论:0      收藏:0      [点我收藏+]

标签:col   rtp   比较   animator   update   rtx   height   iss   ref   

前言

在网页在看见小米动态图的实现,最近正在学习kotlin,就准备自己也实现一个,

参考实现(建议先读):https://blog.csdn.net/u013094278/article/details/75450534

技术图片

一、实现一个三角形的变化:

1、计算三角形坐标

mLength是高,mStartX,mStartY是开始坐标,offset边长,自己设置开始位置

val offset = (mLength * 2 / Math.sqrt(3f.toDouble())).toFloat()
mTriangleEntity.startX = mStartX
mTriangleEntity.startY = mStartY

mTriangleEntity.endX1 = mStartX - mLength
mTriangleEntity.endX2 = mStartX - mLength

mTriangleEntity.endY1 = mStartY - offset / 2
mTriangleEntity.endY2 = mStartY + offset / 2

 

2、使用drawPath来绘制三角形

override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        canvas ?: return
mPath.reset() mPath.moveTo(mTriangleEntity.startX, mTriangleEntity.startY) mPath.lineTo(mTriangleEntity.currentX1, mTriangleEntity.currentY1) mPath.lineTo(mTriangleEntity.currentX2, mTriangleEntity.currentY2) mPaint.color = color1 canvas.drawPath(mPath, mPaint) }

3、使用valueAnimator来生成动态数据,使图形变化

 private fun doAnimator() {
        mValueAnimator.addUpdateListener {
            val data = it.animatedFraction

            mTriangleEntity.apply {
                currentX1 = startX + data * (endX1 - startX)
                currentX2 = startX + data * (endX2 - startX)
                currentY1 = startY + data * (endY1 - startY)
                currentY2 = startY + data * (endY2 - startY)
            }

            invalidate()
        }

        mValueAnimator.start()
    }

二、实现多个三角形

基本原理和一个三角形动态变化是一样的,我们只需要初始化好三角形,然后按照顺序进行相应的变化绘制就可以

1、初始化三角形

一共4个三角形,6个点,先定义start点,其他经过计算出来就行

private fun initTriangle() {

        val offset = (mLength * 2 / Math.sqrt(3f.toDouble())).toFloat()
        //最右边的点
        val point1 = TrianglePoint(mStartX, mStartY)
        //最上面的点
        val point2 = TrianglePoint(mStartX - mLength, mStartY - offset / 2)
        //最下面的点
        val point3 = TrianglePoint(mStartX - mLength, mStartY + offset / 2)

        val point4 = TrianglePoint(mStartX - mLength / 2, mStartY + offset / 4)
        val point6 = TrianglePoint(mStartX - mLength / 2, mStartY - offset / 4)
        val point5 = TrianglePoint(mStartX - mLength, mStartY)

        mTriangles = arrayOfNulls(4)
        mTriangles[0] = TriangleEntity(point4, point6, point5, null, null, color1)
        mTriangles[1] = TriangleEntity(point5, point6, point2, null, null, color2)
        mTriangles[2] = TriangleEntity(point6, point4, point1, null, null, color3)
        mTriangles[3] = TriangleEntity(point4, point5, point3, null, null, color4)

    }

2、执行顺序

用枚举状态来控制执行,设置动画一直执行,在重复回调方法中控制进度

private enum class LoadStatus {
        MID_LOADING,
        FIRST_LOADING,
        SECOND_LOADING,
        THIRD_LOADING,
        THIRD_DISMISS,
        FIRST_DISMISS,
        SECOND_DISMISS,
        MID_DISMISS,
        LOADING_COMPLETE
    }
mValueAnimator.addListener(object : Animator.AnimatorListener {
            override fun onAnimationRepeat(animation: Animator?) {
                LogUtils.e("onAnimationRepeat.....1" + mCurrentStatus.name)
                    mCurrentStatus = when (mCurrentStatus) {
                        LoadStatus.MID_LOADING -> LoadStatus.FIRST_LOADING
                        LoadStatus.FIRST_LOADING -> LoadStatus.SECOND_LOADING
                        LoadStatus.SECOND_LOADING -> LoadStatus.THIRD_LOADING
                        LoadStatus.THIRD_LOADING -> {
                            reverseTriangleStart()
                            LoadStatus.LOADING_COMPLETE
                        }
                        //reverseTriangleStart()
                        LoadStatus.LOADING_COMPLETE -> LoadStatus.THIRD_DISMISS
                        LoadStatus.THIRD_DISMISS -> LoadStatus.FIRST_DISMISS
                        LoadStatus.FIRST_DISMISS -> LoadStatus.SECOND_DISMISS
                        LoadStatus.SECOND_DISMISS -> LoadStatus.MID_DISMISS
                        LoadStatus.MID_DISMISS -> {
                            reverseTriangleStart()
                            LoadStatus.MID_LOADING
                        }
                    }
                }

3、动态变化

 mValueAnimator.addUpdateListener {
            var data = it.animatedFraction
            if (mCurrentStatus.ordinal > 3) {
                data = 1 - data
            }
if (mCurrentStatus != LoadStatus.LOADING_COMPLETE) {
                mTriangles[mCurrentStatus.ordinal % 4]?.run {
                    currentP1 = getCurrentPoint(data, startP, endP1)
                    currentP2 = getCurrentPoint(data, startP, endP2)
                }
                invalidate()
            }


        }

注意红色部分,必须要把枚举状态的顺序固定才能这么写,不然顺序执行有问题。

4、绘制

override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        canvas ?: return
        mTriangles.forEach {
            mPath.reset()
            mPath.moveTo(it.startP.x, it.startP.y)
            mPath.lineTo(it.currentP1!!.x, it.currentP1!!.y)
            mPath.lineTo(it.currentP2!!.x, it.currentP2!!.y)
            mPath.close()
            mPaint.color = it.color
            canvas.drawPath(mPath, mPaint)
            if (mCurrentStatus == LoadStatus.MID_LOADING) {
                return
            }
        }
    }

其实只要熟悉绘制一个三角形的方法,多个只是数学计算和逻辑上的一些控制,难度不大。

主要在中间遇到几个问题:

1、onAnimationRepeat 在重新绘制的时候会调用2次。

主要原因:执行动画在onLayout方法,会导致出现此情况。修改方式:等待显示后在执行动画,正常。(具体原因其实也不清楚,猜测在View绘制的时候就去执行动画,可能会引起绘制的错误)

2、绘制三角形不是完整的,一个三角形可能还看不出,多个时候就比较明显。

主要原因:动画得到data是(0,1)之间的数,导致计算的当前点不等于最终点

解决方法:没找到valueAnimator可用的方法,就在onAnimationRepeat 中把当前点设置成结束点重新绘制一遍。

 

Kotlin动态图

标签:col   rtp   比较   animator   update   rtx   height   iss   ref   

原文地址:https://www.cnblogs.com/doubleyoujs/p/11455851.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!