为了账号安全,请及时绑定邮箱和手机立即绑定

高仿抖音播放(三)——细节的优化

这是第「31篇」原创分享
朝阳杨少爷(ID:CY_YANG_DA_YE),专注于Android领域的开发者。

一篇文章,我们着重实现了 上下滑动播放详情页播放之后自动播放
接下来,我们要实现的就是 双击点赞效果,并且点赞单击暂停,再单击播放这两个功能。

欢迎star

首先,实现以下双击点击的动画效果。
这个动画,可以看到要实现的效果。
图片描述

可以看到,主要有以下几个功能点。

1. 缩放的动画
2. 位移的动画
3. 透明度的动画
4. 还有一个点击的动作的监听

梳理完功能点之后,就比较好实现对应的效果了。

三个动画效果,我们可以直接用ObjectAnimator这个类来实现。

点击效果,自然就涉及到了 dispatchTouchEvent

梳理完要实现的效果和方法之后,详细就看代码。

我们自定义了一个点赞的动画。

package com.yang.dyvideo.widget;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.content.Context;
import android.graphics.Canvas;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import com.yang.dyvideo.R;
import com.yang.dyvideo.presenter.MyClickListener;

import java.util.Random;



/**
 * @author yangzc
 * @data 2019/5/31 13:13
 * @desc
 */
public class VideoLikeView extends RelativeLayout {
    private Context mContext;
    float[] num = {-30, -20, 0, 20, 30};//随机心形图片角度
    //记录上一次的点击时间
    private long  lastClickTime = 0;
    //点击的时间间隔
    private long INTERVAL = 200;
    private MyClickListener.MyClickCallBack onClickListener;

    public VideoLikeView(Context context) {
        super(context);
        initView(context);
    }

    public VideoLikeView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public VideoLikeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    private void initView(Context context) {
        mContext = context;
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                //获取点击时间
                long currTime = System.currentTimeMillis();
                //判断点击之间的时间差
                long  interval = currTime - lastClickTime;
                lastClickTime = currTime;
                if(interval <INTERVAL ){
                    final ImageView imageView = new ImageView(mContext);
                    //设置展示的位置,需要在手指触摸的位置上方,即触摸点是心形的右下角的位置
                    LayoutParams params = new LayoutParams(300, 300);
                    params.leftMargin = (int) event.getX() - 150;
                    params.topMargin = (int) event.getY() - 300;
                    //设置图片资源
                    imageView.setImageDrawable(getResources().getDrawable(R.mipmap.ic_heart));
                    imageView.setLayoutParams(params);
                    //把IV添加到父布局当中
                    addView(imageView);
                    //设置控件的动画
                    AnimatorSet animatorSet = new AnimatorSet();
                    //缩放动画,X轴2倍缩小至0.9倍
                    animatorSet.play(scale(imageView, "scaleX", 2f, 0.9f, 100, 0))
                            //缩放动画,Y轴2倍缩放至0.9倍
                            .with(scale(imageView, "scaleY", 2f, 0.9f, 100, 0))
                            //旋转动画,随机旋转角
                            .with(rotation(imageView, 0, 0, num[new Random().nextInt(4)]))
                            //渐变透明动画,透明度从0-1
                            .with(alpha(imageView, 0, 1, 100, 0))
                            //缩放动画,X轴0.9倍缩小至
                            .with(scale(imageView, "scaleX", 0.9f, 1, 50, 150))
                            //缩放动画,Y轴0.9倍缩放至
                            .with(scale(imageView, "scaleY", 0.9f, 1, 50, 150))
                            //位移动画,Y轴从0上移至600
                            .with(translationY(imageView, 0, -600, 800, 400))
                            //透明动画,从1-0
                            .with(alpha(imageView, 1, 0, 300, 400))
                            //缩放动画,X轴1至3倍
                            .with(scale(imageView, "scaleX", 1, 3f, 700, 400))
                            //缩放动画,Y轴1至3倍
                            .with(scale(imageView, "scaleY", 1, 3f, 700, 400));
                    //开始动画
                    animatorSet.start();
                    //设置动画结束监听
                    animatorSet.addListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            super.onAnimationEnd(animation);
                            //当动画结束以后,需要把控件从父布局移除
                            removeViewInLayout(imageView);
                        }
                    });
                }
                break;
        }
        return super.dispatchTouchEvent(event);
    }
    /**
     * 缩放动画
     * @param view
     * @param propertyName
     * @param from
     * @param to
     * @param time
     * @param delayTime
     * @return
     */
    public static ObjectAnimator scale(View view, String propertyName, float from, float to, long time, long delayTime) {
        ObjectAnimator translation = ObjectAnimator.ofFloat(view
                , propertyName
                , from, to);
        translation.setInterpolator(new LinearInterpolator());
        translation.setStartDelay(delayTime);
        translation.setDuration(time);
        return translation;
    }
    /**
     * 位移动画
     * @param view
     * @param from
     * @param to
     * @param time
     * @param delayTime
     * @return
     */
    public static ObjectAnimator translationX(View view, float from, float to, long time, long delayTime) {
        ObjectAnimator translation = ObjectAnimator.ofFloat(view
                , "translationX"
                , from, to);
        translation.setInterpolator(new LinearInterpolator());
        translation.setStartDelay(delayTime);
        translation.setDuration(time);
        return translation;
    }
    public static ObjectAnimator translationY(View view, float from, float to, long time, long delayTime) {
        ObjectAnimator translation = ObjectAnimator.ofFloat(view
                , "translationY"
                , from, to);
        translation.setInterpolator(new LinearInterpolator());
        translation.setStartDelay(delayTime);
        translation.setDuration(time);
        return translation;
    }
    /**
     * 透明度动画
     * @param view
     * @param from
     * @param to
     * @param time
     * @param delayTime
     * @return
     */
    public static ObjectAnimator alpha(View view, float from, float to, long time, long delayTime) {
        ObjectAnimator translation = ObjectAnimator.ofFloat(view
                , "alpha"
                , from, to);
        translation.setInterpolator(new LinearInterpolator());
        translation.setStartDelay(delayTime);
        translation.setDuration(time);
        return translation;
    }
    public static ObjectAnimator rotation(View view, long time, long delayTime, float... values) {
        ObjectAnimator rotation = ObjectAnimator.ofFloat(view, "rotation", values);
        rotation.setDuration(time);
        rotation.setStartDelay(delayTime);
        rotation.setInterpolator(new TimeInterpolator() {
            @Override
            public float getInterpolation(float input) {
                return input;
            }
        });
        return rotation;
    }
    public void setOnClickListener(MyClickListener.MyClickCallBack onClickListener) {
        this.onClickListener = onClickListener;
    }
    public MyClickListener.MyClickCallBack getOnClickListener() {
        return onClickListener;
    }
}

接下来,我们就要实现单击暂停、播放的功能

因为这个功能也涉及到了的点击,所以,我们就需要区分一下在屏幕上是双击,还是单击。

双击就是点赞的动画,单击就是播放、暂停的功能。

在这里,采用的HandlerpostDelayed方法,来区分两次点击之间的延时点击时间timeout,同时设计一个连续点击的计数器clickCount来记录在timeout的时间里的点击次数。clickCount为1则是播放、暂停的方法,如果 clickCount为2 则为点赞的效果。

理清了思路,接下来我们看一下实现的代码。

  mAdapter!!.setOnItemClickListener(object : VideoPlayAdapter.OnItemClickListener {
             var timeout = 500//双击间百毫秒延时
             var clickCount = 0//记录连续点击次数
             var handler = Handler()

            override fun onItemClick(view: View, position: Int) {
                clickCount++
                val mini_surface_view = view.findViewById<FullWindowVideoView>(R.id.surface_view)
                view.setOnTouchListener { v, event ->
                    if (event.action == MotionEvent.ACTION_DOWN) {
                        handler.postDelayed({
                            if (clickCount == 1) {
                                if (mini_surface_view.isPlaying()) {
                                    mini_surface_view.pause()
                                    iv_video_play.setVisibility(View.VISIBLE)
                                } else {
                                    iv_video_play.setVisibility(View.GONE)
                                    val mediaPlayer = arrayOfNulls<MediaPlayer>(1)
                                    mini_surface_view.setOnPreparedListener(MediaPlayer.OnPreparedListener { })
                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                                        mini_surface_view.setOnInfoListener(MediaPlayer.OnInfoListener { mp, what, extra ->
                                            mediaPlayer[0] = mp
                                            mp.isLooping = true
                                            mp.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT)
                                            false
                                        })
                                    }
                                    mini_surface_view.start()
                                }
                            } else if (clickCount >= 2) {
                                if (!videolist?.get(position)!!.like) {
                                    praiseMethod(position)
                                }
                            }
                            handler.removeCallbacksAndMessages(null)
                            //清空handler延时,并防内存泄漏
                            clickCount = 0//计数清零
                        }, timeout.toLong())//延时timeout后执行run方法中的代码
                    }
                    false
                }
            }
        })

至此,我们要实现的整个功能都完成了。

欢迎**“点赞”、“关注”**。

如果要有任何问题、BUG欢迎给我留言。

点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
35
获赞与收藏
116

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消