Android 利用ConstraintLayout 實現仿抖音點贊動畫效果

正好在做一個和抖音差不多的APP,目前在剛啓動階段,先從實現一個抖音的點贊動畫開始。。。愛心是從阿里的矢量圖標庫下載的一個愛心的Png圖片,不是使用貝塞爾曲線畫的。。。原因是我不會貝塞爾曲線(其實就是菜)我使用的是Androidx的包,如果使用的老的Support的包,請自行替換。代碼是kotlin實現的,需要java的請自行翻譯。最後使用方式,就是在xml文件中直接當成ConstraintLayout使用,就會自帶點贊效果了。

觀察一下抖音的點贊效果,實際上就是雙擊2下以上會觸發那個點讚的動畫,然後包含先從大縮小到正常大小再放大,隨機的左右搖擺的動畫,還有漸變的動畫。所以我們只需要繼承ConstrantLayout在Ontouchevent方法中實現動畫就OK了。

 

 

代碼如下

package tracyeminem.com.peipei.view

import android.animation.*
import android.content.Context
import android.os.SystemClock
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.view.animation.LinearInterpolator
import android.widget.ImageView
import androidx.constraintlayout.widget.ConstraintLayout
import tracyeminem.com.peipei.R
import kotlin.random.Random

class LoveView(context: Context) : ConstraintLayout(context){

    var mContext : Context ?= null

    //隨機愛心的旋轉角度
    var num = floatArrayOf(-35f,-25f,0f,25f,35f)

    //判斷是否是連續的點擊事件
    private val mHits = LongArray(2)

    constructor(context: Context,attrs : AttributeSet) : this(context) {
        mContext = context
    }

    //用這個來判斷是否是雙擊事件,判斷數組中pos=1的點擊事件的時間與數組中pos=0的點擊事件的時間差值是否小於500,若是小於500認爲是雙擊事件,這時需要繪製愛心圖片
    override fun onTouchEvent(event: MotionEvent?): Boolean {


        System.arraycopy(mHits,1,mHits,0,mHits.size-1)
        mHits[mHits.size-1] = SystemClock.uptimeMillis()

        if(mHits[0] >= (SystemClock.uptimeMillis() - 500)){

            var iv = ImageView(context)


            //設置展示圖片的大小
            var lp = LayoutParams(300,300)

            //設置圖片的相對座標是父佈局的左上角開始的
            lp.leftToLeft = 0
            lp.topToTop = 0

            //設置圖片相對於點擊位置的座標
            lp.leftMargin = (event?.x!! - 150F).toInt()
            lp.topMargin = (event.y!! - 230F).toInt()

            //設置圖片資源
            iv.setImageDrawable(resources.getDrawable(R.drawable.heart_red))
            iv.layoutParams = lp

            //把IV添加到父佈局中
            addView(iv)

            var animatorSet = AnimatorSet()
            animatorSet.play(
                scaleAni(iv,"scaleX",2f,0.9f,100,0))
                .with(scaleAni(iv,"scaleY",2f,0.9f,100,0))
                .with(rotation(iv,0,0,num[Random.nextInt(4)]))
                .with(alphaAni(iv,0F,1F,100,0))
                .with(scaleAni(iv,"scaleX",0.9f,1F,50,150))
                .with(scaleAni(iv,"scaleY",0.9f,1F,50,150))
                .with(translationY(iv,0f,-600F,800,400))
                .with(alphaAni(iv,1F,0F,300,400))
                .with(scaleAni(iv,"scaleX",1F,3f,700,400))
                .with(scaleAni(iv,"scaleY",1F,3f,700,400))


            animatorSet.start()

            animatorSet.addListener(object :AnimatorListenerAdapter(){
                override fun onAnimationEnd(animation: Animator?) {
                    super.onAnimationEnd(animation)
                    //當動畫結束,把控件從父佈局移除
                    removeViewInLayout(iv)
                }
            })

        }

        return super.onTouchEvent(event)
    }

    //vararg可變參數修飾符,此處可以傳入多個Float類型值
    fun rotation(view:View,time:Long,delayTime:Long,vararg values:Float):ObjectAnimator{
        val ani = ObjectAnimator.ofFloat(view,"rotation",*values)
        ani.duration = time
        ani.startDelay = delayTime
        ani.interpolator = TimeInterpolator { input -> input }
        return ani
    }

    fun alphaAni(view : View,from : Float,to : Float,time: Long,delayTime: Long):ObjectAnimator{
        val ani = ObjectAnimator.ofFloat(view,"alpha",from,to)
        ani.interpolator = LinearInterpolator()
        ani.duration = time
        ani.startDelay = delayTime
        return ani
    }

    fun translationY(view: View,from: Float,to: Float,time: Long,delayTime: Long):ObjectAnimator{
        val ani = ObjectAnimator.ofFloat(view,"translationY",from,to)
        ani.interpolator = LinearInterpolator()
        ani.startDelay =  delayTime
        ani.duration = time
        return ani
    }

    fun translationX(view: View,from: Float,time: Long,to: Float,delayTime: Long):ObjectAnimator{
        val ani = ObjectAnimator.ofFloat(view,"translationX",from,to)
        ani.startDelay = delayTime
        ani.duration = time
        ani.interpolator = LinearInterpolator()
        return ani
    }

    fun scaleAni(view: View,propertyName:String,from: Float,to: Float,time: Long,delayTime: Long):ObjectAnimator{
        val ani = ObjectAnimator.ofFloat(view,propertyName,from,to)
        ani.interpolator = LinearInterpolator()
        ani.startDelay = delayTime
        ani.duration = time
        return ani
    }


}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章