zoukankan      html  css  js  c++  java
  • Kotlin动态图

    前言

    在网页在看见小米动态图的实现,最近正在学习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绘制的时候就去执行动画,可能会引起绘制的错误)

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

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

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

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

  • 相关阅读:
    JQuery的学习笔记
    Ajax的学习笔记
    软件项目的托管平台gitHub
    滚动事件:document.body.scrollTop总是0的原因
    Less/Sass编译工具,koala使用指南
    CSS中的浮动和清除浮动,梳理一下
    PHP_GET数据获取
    php中header()
    服务端web开发:PHP简介以及常见语法
    C/S架构和B/S架构
  • 原文地址:https://www.cnblogs.com/doubleyoujs/p/11455851.html
Copyright © 2011-2022 走看看