抖音,能夠說目前最火的短視頻APP!做爲一名 Android 開發,是時候研究一下功能是如何實現的了!
目前,也有一些其餘的小夥伴實現都有播放的效果,只要是用 ViewPager 來實現的上下滑動。 今天,咱們換個思路用咱們最經常使用的控件,RecyclerView 來實現,下面先看看須要實現的功能。java
抖音,能夠說目前最火的短視頻APP!做爲一名 Android 開發,是時候研究一下功能是如何實現的了!
目前,也有一些其餘的小夥伴實現都有播放的效果,只要是用 ViewPager 來實現的上下滑動。 今天,咱們換個思路用咱們最經常使用的控件,RecyclerView 來實現,下面先看看須要實現的功能。android
打開抖音看一下,大體都有什麼功能。git
這是抖音的播放頁面,能夠看到大體有如下幾個功能。github
1. 上下滑動播放詳情頁
2. 播放以後自動播放
3. 雙擊點贊效果,而且點贊
4. 單擊暫停,再單擊播放canvas
下面對比一下,我實現的效果bash
基本上完成了咱們咱們預先想實現的需求。網絡
GitHub地址:github.com/yang0range/…app
歡迎star!dom
若是須要想看看實現原理那就請繼續看下一篇。ide
GitHub地址:github.com/yang0range/…
歡迎star!
上一篇,文章展現了實現的效果,而且陳列了咱們要實現的功能。接下來經過兩篇文章,詳細的實現如下整個的過程。
建立項目,由於播放視頻要在網絡播放,因此須要添加網絡權限。
<uses-permission android:name="android.permission.INTERNET" />
複製代碼
建立BaseAcivity
package com.yang.dyvideo.activity
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
/**
* @author yangzc
* @data 2019/9/26 18:35
* @desc BaseAcivity
*
*/
abstract class BaseAcivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(layoutId())
initData()
initView()
start()
initListener()
}
abstract fun initListener()
/**
* 初始化數據
*/
abstract fun initData()
/**
* 初始化 View
*/
abstract fun initView()
/**
* 開始請求
*/
abstract fun start()
/**
* 加載佈局
*/
open fun layoutId(): Int {
return 0
}
}
複製代碼
首頁的列表頁
package com.yang.dyvideo.activity
import android.support.v7.widget.LinearLayoutManager
import android.view.View
import com.yang.dyvideo.R
import com.yang.dyvideo.adapter.VideoAdapter
import com.yang.dyvideo.data.Video
import com.yang.dyvideo.data.VideoDataProvider
import kotlinx.android.synthetic.main.activity_main.*
import java.util.*
class MainActivity : BaseAcivity() {
private var videolist: MutableList<Video>? = null
private var mAdapter: VideoAdapter? = null
override fun initListener() {
mAdapter?.let {
it.setOnItemClickListener(object : VideoAdapter.OnItemClickListener {
override fun onItemClick(view: View, position: Int, mVideo: Video) {
startActivity(VideoPlayActivity.buildIntent(this@MainActivity, position, videolist as ArrayList<Video>?))
}
})
}
}
override fun initData() {
videolist = ArrayList()
for (i in 0 until 15) {
val mVideo = Video()
mVideo.iamge = VideoDataProvider.getVideoListImg(this).getResourceId(i, R.mipmap.one)
mVideo.title = VideoDataProvider.getVideoListTitle(this).getString(i)
mVideo.videoplayer = VideoDataProvider.getVideoPlayer(this).getString(i)
(videolist as ArrayList<Video>).add(mVideo)
}
}
override fun initView() {
}
override fun start() {
mAdapter = videolist?.let { VideoAdapter(this, it) }
rlv.adapter = mAdapter
val linearLayoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
rlv.layoutManager = linearLayoutManager
}
override fun layoutId(): Int {
return R.layout.activity_main
}
}
複製代碼
首頁的Adapter
package com.yang.dyvideo.adapter
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import com.yang.dyvideo.R
import com.yang.dyvideo.data.Video
/**
* @author yangzc
* @data 2019/9/27 11:17
* @desc
*/
class VideoAdapter(private val mContext: Context, private val mVideoList: List<Video>) : RecyclerView.Adapter<VideoAdapter.VideoPlayerViewHolder>() {
private var onItemClickListener: OnItemClickListener? = null
//點擊事件的接口
interface OnItemClickListener {
fun onItemClick(view: View, position: Int, mVideo: Video)
}
fun setOnItemClickListener(listener: OnItemClickListener) {
this.onItemClickListener = listener
}
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): VideoPlayerViewHolder {
return VideoPlayerViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_video_list, viewGroup, false))
}
override fun onBindViewHolder(ViewHolder: VideoPlayerViewHolder, position: Int) {
val mVideo = mVideoList[position]
ViewHolder.dy_iv.setImageResource(mVideo.iamge)
ViewHolder.dy_tv.text = mVideo.title
setOnItemClick(ViewHolder)
}
private fun setOnItemClick(holder: VideoPlayerViewHolder) {
if (this.onItemClickListener != null) {
holder.itemView.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View) {
run {
val position = holder.layoutPosition
this@VideoAdapter.onItemClickListener!!.onItemClick(holder.itemView, position, mVideoList[position])
}
}
})
}
}
override fun getItemCount(): Int {
return if (mVideoList.isEmpty()) 0 else mVideoList.size
}
inner class VideoPlayerViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {
internal val dy_iv: ImageView = itemView.findViewById(R.id.dy_iv)
internal val dy_tv: TextView = itemView.findViewById(R.id.dy_tv)
}
}
複製代碼
實現需求——上下滑動播放詳情頁
這幾部分沒有什麼可說的,都是常規的實現方式。接下來,咱們來看看最主要的播放的詳情頁的實現。
接下來,看看咱們的詳情頁的佈局.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#2D2D33"
tools:ignore="MissingConstraints,ContentDescription">
<android.support.v7.widget.RecyclerView
android:id="@+id/rlv_play_video"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="beforeDescendants" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="parent">
<ImageView
android:id="@+id/iv_user_avatar"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@mipmap/default_avater" />
<ImageView
android:id="@+id/iv_user_follow"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:src="@mipmap/ic_love_white" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:text="@string/num"
android:textColor="@color/colorWhite"
android:textSize="14sp" />
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="15dp"
android:src="@mipmap/ic_comment" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:text="@string/num"
android:textColor="@color/colorWhite"
android:textSize="14sp" />
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:src="@mipmap/ic_share" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:text="@string/num"
android:textColor="@color/colorWhite"
android:textSize="14sp" />
</LinearLayout>
<ImageView
android:id="@+id/iv_video_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/ic_video_play"
android:visibility="visible"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintLeft_toRightOf="parent"
app:layout_constraintRight_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="parent" />
</android.support.constraint.ConstraintLayout>
複製代碼
以前,介紹過咱們此次採用的是 RecyclerView來實現的效果。
詳情的播放頁,才用的是Android自帶的VideoView,爲了實現咱們想要的全屏的效果,咱們須要簡單的自定義一下。
package com.yang.dyvideo.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.VideoView;
public class FullWindowVideoView extends VideoView {
public FullWindowVideoView(Context context) {
super(context);
}
public FullWindowVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FullWindowVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
複製代碼
那接下來看一下Adapter的佈局的實現
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.yang.dyvideo.widget.FullWindowVideoView
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/iv_video_cover"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="false"
android:focusable="false"
android:scaleType="centerInside"
android:visibility="visible" />
</android.support.constraint.ConstraintLayout>
複製代碼
在播放頁面,咱們添加了一個播放的按鈕。
再看看Adapter當中的代碼
package com.yang.dyvideo.adapter
import android.content.Context
import android.media.MediaPlayer
import android.net.Uri
import android.os.Build
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import com.yang.dyvideo.R
import com.yang.dyvideo.data.Video
import com.yang.dyvideo.widget.FullWindowVideoView
/**
* @author yangzc
* @data 2019/9/29 15:25
* @desc
*/
class VideoPlayAdapter (private val mContext: Context, private val mVideoList: List<Video>): RecyclerView.Adapter<VideoPlayAdapter.VideoPlayAdapterViewHolder>() {
private var onItemClickListener: OnItemClickListener? = null
fun setOnItemClickListener(listener: OnItemClickListener) {
this.onItemClickListener = listener
}
interface OnItemClickListener {
fun onItemClick(view: View, position: Int)
}
override fun onBindViewHolder(mViewHolder: VideoPlayAdapterViewHolder, position: Int) {
val mVideo = mVideoList[position]
mViewHolder.iv_video_cover.setImageResource(mVideo.iamge)
mViewHolder.surface_view.setVideoURI(Uri.parse(mVideo.videoplayer))
// mViewHolder.surface_view.setVideoURI(Uri.parse("http://jzvd.nathen.cn/b201be3093814908bf987320361c5a73/2f6d913ea25941ffa78cc53a59025383-5287d2089db37e62345123a1be272f8b.mp4"))
if (!mViewHolder.surface_view.isPlaying()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
mViewHolder.surface_view.setOnPreparedListener { mp ->
mp.setOnInfoListener(MediaPlayer.OnInfoListener { mp, what, extra ->
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
mp.isLooping = true
mViewHolder.iv_video_cover.animate().alpha(0f).setDuration(0).start()
mp.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT)
return@OnInfoListener true
}
false
})
}
}
mViewHolder.surface_view.start()
}
setOnItemClick(mViewHolder)
}
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int):VideoPlayAdapterViewHolder {
return VideoPlayAdapterViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_video_play, viewGroup, false))
}
override fun getItemCount(): Int {
return if (mVideoList.isEmpty()) 0 else mVideoList.size
}
protected fun setOnItemClick(holder: VideoPlayAdapterViewHolder) {
if (onItemClickListener != null) {
//爲holder增長點擊事件
//爲了保持插入和刪除的position正確 不採用getview的position
holder.itemView.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View) {
run {
val position = holder.getLayoutPosition()
onItemClickListener!!.onItemClick(holder.itemView, position)
}
}
})
}
}
inner class VideoPlayAdapterViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {
internal val surface_view : FullWindowVideoView = itemView.findViewById(R.id.surface_view)
internal val iv_video_cover : ImageView = itemView.findViewById(R.id.iv_video_cover)
}
}
複製代碼
Adapter已經完成,接下來再看看如何自動實現上下滑動的時候
咱們須要自定一下LayoutManager,經過自定義 LayoutManager 來實現咱們對於 RecyclerView的滑動監聽
package com.yang.dyvideo.utils
import android.content.Context
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.PagerSnapHelper
import android.support.v7.widget.RecyclerView
import android.view.View
import com.yang.dyvideo.presenter.OnViewPagerListener
/**
* @author yangzc
* @data 2019/5/29 14:14
* @desc
*
*/
class MyLayoutManager : LinearLayoutManager, RecyclerView.OnChildAttachStateChangeListener {
constructor(context: Context) : super(context)
constructor(context: Context, @RecyclerView.Orientation orientation: Int,
reverseLayout: Boolean) : super(context, orientation, reverseLayout) {
pagerSpaner = PagerSnapHelper()
}
var pagerSpaner: PagerSnapHelper? = null
var viewPagerListener: OnViewPagerListener? = null
var diffY = 0
override fun onAttachedToWindow(view: RecyclerView) {
super.onAttachedToWindow(view)
view.addOnChildAttachStateChangeListener(this)
pagerSpaner!!.attachToRecyclerView(view)
}
override fun onChildViewDetachedFromWindow(p0: View) {
val position = getPosition(p0)
if (0 < diffY) {
viewPagerListener?.onPageRelease(true, position)
} else {
viewPagerListener?.onPageRelease(false, position)
}
}
override fun onChildViewAttachedToWindow(p0: View) {
val position = getPosition(p0)
if (0 == position) {
viewPagerListener?.onPageSelected(position, false)
}
}
override fun onScrollStateChanged(state: Int) {
if (RecyclerView.SCROLL_STATE_IDLE == state) {
val view = pagerSpaner!!.findSnapView(this)
val position = getPosition(view!!)
viewPagerListener?.onPageSelected(position, position == itemCount - 1)
}
super.onScrollStateChanged(state)
}
fun setOnViewPagerListener(listener: OnViewPagerListener) {
viewPagerListener = listener
}
override fun scrollVerticallyBy(dy: Int, recycler: RecyclerView.Recycler?, state: RecyclerView.State?): Int {
diffY = dy
return super.scrollVerticallyBy(dy, recycler, state)
}
}
複製代碼
定義完成以後,須要實現播放和中止播放的兩個方法,這兩個方法相對就比較簡單了,分別是
releaseVideo
private fun releaseVideo(index: Int) {
val itemView = rlv_play_video.getChildAt(index)
val videoView = itemView.findViewById<FullWindowVideoView>(R.id.surface_view)
val imgThumb = itemView.findViewById<ImageView>(R.id.iv_video_cover)
videoView.stopPlayback()
imgThumb.animate().alpha(1f).start()
}
複製代碼
playVideo
private fun playVideo(position: Int) {
val itemView = rlv_play_video.getChildAt(position)
val videoView = itemView.findViewById<FullWindowVideoView>(R.id.surface_view)
val imgThumb = itemView.findViewById<ImageView>(R.id.iv_video_cover)
val mediaPlayer = arrayOfNulls<MediaPlayer>(1)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
videoView.setOnInfoListener { mp, what, extra ->
mediaPlayer[0] = mp
mp.isLooping = true
imgThumb.animate().alpha(0f).start()
mp.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT)
false
}
}
videoView.start()
if (iv_video_play.visibility == View.VISIBLE) {
iv_video_play.visibility = View.GONE
}
}
複製代碼
結合咱們以前自定義的滑動監聽,就能夠實現 上下滑動播放詳情頁的效果了
this.myLayoutManager?.setOnViewPagerListener(object : OnViewPagerListener {
override fun onInitComplete() {
}
override fun onPageRelease(isNext: Boolean, position: Int) {
var index: Int
index = if (isNext) {
0
} else {
1
}
releaseVideo(index)
}
override fun onPageSelected(position: Int, bottom: Boolean) {
playVideo(0)
}
})
複製代碼
截止目前爲止,咱們須要實現的第一個需求 上下滑動播放詳情頁已經實現了。
上一篇文章,咱們着重實現了 上下滑動播放詳情頁, 播放以後自動播放 接下來,咱們要實現的就是 雙擊點贊效果,而且點贊, 單擊暫停,再單擊播放這兩個功能。
GitHub地址:github.com/yang0range/…
歡迎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;
}
}
複製代碼
接下來,咱們就要實現單擊暫停、播放的功能
由於這個功能也涉及到了的點擊,因此,咱們就須要區分一下在屏幕上是雙擊,仍是單擊。
雙擊就是點讚的動畫,單擊就是播放、暫停的功能。
在這裏,採用的Handler的postDelayed方法,來區分兩次點擊之間的延時點擊時間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歡迎給我留言。