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
    }


}

 

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实现仿抖音双击点赞特效,可以使用Android中的GestureDetector类,它可以检测手势事件。具体实现步骤如下: 1.在布局文件中,创建一个ImageView控件,并设置图片资源。 2.在Java代码中,实例化GestureDetector类,并在onTouchEvent()方法中传入MotionEvent事件。 3.在GestureDetector的onDoubleTap()方法中,实现双击点赞的逻辑。 4.在GestureDetector的onSingleTapConfirmed()方法中,实现单击事件的逻辑。 下面是实现代码示例: ``` public class MainActivity extends AppCompatActivity implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener { ImageView imageView; GestureDetector gestureDetector; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = findViewById(R.id.imageView); gestureDetector = new GestureDetector(this, this); gestureDetector.setOnDoubleTapListener(this); } @Override public boolean onTouchEvent(MotionEvent event) { gestureDetector.onTouchEvent(event); return super.onTouchEvent(event); } @Override public boolean onSingleTapConfirmed(MotionEvent e) { // 单击事件逻辑 return true; } @Override public boolean onDoubleTap(MotionEvent e) { // 双击事件逻辑 return true; } @Override public boolean onDoubleTapEvent(MotionEvent e) { return true; } @Override public boolean onDown(MotionEvent e) { return true; } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { return true; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return true; } @Override public void onLongPress(MotionEvent e) { } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return true; } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值