Kotlin动态图

Posted doubleyoujs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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绘制的时候就去执行动画,可能会引起绘制的错误)

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

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

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

 

以上是关于Kotlin动态图的主要内容,如果未能解决你的问题,请参考以下文章

pytorch 计算图与动态图机制

动态图GIF动态图怎么做?上传动态效果图到你的csdn?

动态图GIF动态图怎么做?上传动态效果图到你的csdn?

SWT Canvas绘制动态图的问题

KRPano动态热点专用素材图50多个,加动态热点使用方法

iOS GIF动态图(显示、上传、保存)