仿抖音点赞❤️❤️效果

465 阅读3分钟

开玩笑的说

身为一名ui仔,要有ui仔的态度,我本着开源的态度,让我的低代码去污染大家的眼睛,嘿嘿嘿嘿。我要同步大佬的技术,慢慢的拉成和我一致,我就不会被优化了

需求背景

最近因为业务需求,需要实现一个类似抖音的点赞效果,就是那个爱心噗噗往外蹦的那个。那就写写吧。

一、我们需要一个爱心出去的偏移效果

二、我们还需要判断是不是连点

三、处理touch事件

四、动画效果

五、就是咱们需要的事件回调了

接下来就是贴代码的时间了

/**
 * 仿抖音点赞特效
 * */
class LoveView(context: Context, @Nullable attrs: AttributeSet?, defStyleAttr: Int) :
    ConstraintLayout(context, attrs, defStyleAttr) {
    constructor(context: Context) : this(context, null)
    constructor(context: Context, @Nullable attrs: AttributeSet?) : this(context, attrs, 0)


    //随机爱心的旋转角度
    var num = floatArrayOf(-35f, -25f, 0f, 25f, 35f)

    //判断是否是连续的点击事件
    private val mHits = LongArray(2)


    var loveListener: LoveListener? = null

    var isAdd = 1

    //用这个来判断是否是双击事件,判断数组中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() - 200)) {

            var iv = ImageView(context)


            //设置展示图片的大小
            var lp = LayoutParams(250, 250)

            //设置图片的相对坐标是父布局的左上角开始的
            lp.leftToLeft = 0
            lp.topToTop = 0

            //设置图片相对于点击位置的坐标
            lp.leftMargin = (event?.x!! - 150F).toInt()
            lp.topMargin = (event.y - 230F).toInt()

            //设置图片资源
            iv.setImageDrawable(resources.getDrawable(R.drawable.icon_moment_love))
            iv.layoutParams = lp

            //把IV添加到父布局中
            when (isAdd) {
                0 -> {
                    addView(iv)
                    loveListener?.click()
                    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)
                        }
                    })
                    isAdd++
                }
                1 -> {
                    isAdd++
                }
                else -> {
                    isAdd = 0
                }
            }
            return true
        }
        isAdd = 0
        return super.onTouchEvent(event)
    }


    fun setLoveClick(loveListener: LoveListener) {
        this.loveListener = loveListener
    }

    fun interface LoveListener {
        fun click()
    }

    //vararg可变参数修饰符,此处可以传入多个Float类型值
    private 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
    }

    private 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
    }


}
```
```

言简意赅,反正大家懒得看,我就不细说了,大家如果有问题可以评论,我看到回复的,祝大家事事平安