博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Kotlin动态图
阅读量:5089 次
发布时间:2019-06-13

本文共 5388 字,大约阅读时间需要 17 分钟。

前言

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

参考实现(建议先读):

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

1、计算三角形坐标

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

val offset = (mLength * 2 / Math.sqrt(3f.toDouble())).toFloat()mTriangleEntity.startX = mStartXmTriangleEntity.startY = mStartYmTriangleEntity.endX1 = mStartX - mLengthmTriangleEntity.endX2 = mStartX - mLengthmTriangleEntity.endY1 = mStartY - offset / 2mTriangleEntity.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绘制的时候就去执行动画,可能会引起绘制的错误)

(后续在研究view的绘制过程中发现,view的onMeasure onLayout至少会执行两次导致)

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

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

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

 

转载于:https://www.cnblogs.com/doubleyoujs/p/11455851.html

你可能感兴趣的文章
js获取select标签选中的值
查看>>
逆向知识第一讲,IDA的熟悉使用
查看>>
03-numpy-笔记-expand_dims
查看>>
程序的性能优化之代码上的细节优化
查看>>
hibernate4.3版本构造SessionFactory方法
查看>>
Service通信详解
查看>>
前端知识体系
查看>>
职业道德素养
查看>>
MVC View与Controller分离
查看>>
php生命周期
查看>>
测试转型之路--学习ing
查看>>
java、myeclipse项目文件没有错,但是项目名有红叉叉
查看>>
关于C/C++中求最大公约数和最小公倍数的算法
查看>>
mui框架的input输入框为什么会自动触发页面刷新?
查看>>
webpack4+ 学习1
查看>>
Python学习(十三) —— 网络编程
查看>>
Flutter Image(图片)
查看>>
exists的用法
查看>>
吴裕雄 python 机器学习——集成学习梯度提升决策树GradientBoostingClassifier分类模型...
查看>>
吴裕雄--天生自然 JAVASCRIPT开发学习: JSON
查看>>