仿抖音上下滑动播放视频

先看效果图

 

gif2.gif

 

gif1.gif

 

gif3.gif

这里demo下载地址

讲下大概思路,使用recycleview配合自定义LinearLayoutManager来实现这个功能,这里着重说下自定义LinearLayoutManager的实现

可以看到每当下一个item滑入屏幕时,上面的item会继续播放视频,而滑入的item只有当全部进入屏幕才会播放,而且当手指抬起时,当前item会根据滑动的距离相应的自动滑入滑出,针对这种情形,就会想到使用SnapHelper

RecyclerView在24.2.0版本中新增了SnapHelper这个辅助类,用于辅助RecyclerView在滚动结束时将Item对齐到某个位置。特别是列表横向滑动时,很多时候不会让列表滑到任意位置,而是会有一定的规则限制,这时候就可以通过SnapHelper来定义对齐规则了。

SnapHelper是一个抽象类,官方提供了一个LinearSnapHelper的子类,可以让RecyclerView滚动停止时相应的Item停留中间位置。25.1.0版本中官方又提供了一个PagerSnapHelper的子类,可以使RecyclerView像ViewPager一样的效果,一次只能滑一页,而且居中显示,也就是说使用SnapHelper可以帮助recyclerView滑动完成后进行对齐操作,让item的侧边对齐或者居中对齐,这样实现上下滑动进行视频切换。这里有snapHelper的详解

正式撸代码:

1.首先定义一个接口,用来执行item的相关操作


 
 
  1. public interface OnViewPagerListener {
  2. /*初始化完成*/
  3. void onInitComplete();
  4. /*释放的监听*/
  5. void onPageRelease(boolean isNext, int position);
  6. /*选中的监听以及判断是否滑动到底部*/
  7. void onPageSelected(int position, boolean isBottom);
  8. }

2.继承LinearLayoutManager ,对滑入滑出的item回调1中接口里面的方法


 
 
  1. import android.content.Context;
  2. import android.support.annotation.NonNull;
  3. import android.support.v7.widget.LinearLayoutManager;
  4. import android.support.v7.widget.PagerSnapHelper;
  5. import android.support.v7.widget.RecyclerView;
  6. import android.view.View;
  7. public class MyLayoutManager extends LinearLayoutManager implements RecyclerView.OnChildAttachStateChangeListener {
  8. private int mDrift; //位移,用来判断移动方向
  9. private PagerSnapHelper mPagerSnapHelper;
  10. private OnViewPagerListener mOnViewPagerListener;
  11. public MyLayoutManager(Context context) {
  12. super(context);
  13. }
  14. public MyLayoutManager(Context context, int orientation, boolean reverseLayout) {
  15. super(context, orientation, reverseLayout);
  16. mPagerSnapHelper = new PagerSnapHelper();
  17. }
  18. @Override
  19. public void onAttachedToWindow(RecyclerView view) {
  20. view.addOnChildAttachStateChangeListener( this);
  21. mPagerSnapHelper.attachToRecyclerView(view);
  22. super.onAttachedToWindow(view);
  23. }
  24. //当Item添加进来了 调用这个方法
  25. //
  26. @Override
  27. public void onChildViewAttachedToWindow(@NonNull View view) {
  28. // 播放视频操作 即将要播放的是上一个视频 还是下一个视频
  29. int position = getPosition(view);
  30. if ( 0 == position) {
  31. if (mOnViewPagerListener != null) {
  32. mOnViewPagerListener.onPageSelected(getPosition(view), false);
  33. }
  34. }
  35. }
  36. public void setOnViewPagerListener(OnViewPagerListener mOnViewPagerListener) {
  37. this.mOnViewPagerListener = mOnViewPagerListener;
  38. }
  39. @Override
  40. public void onScrollStateChanged(int state) {
  41. switch (state) {
  42. case RecyclerView.SCROLL_STATE_IDLE:
  43. View view = mPagerSnapHelper.findSnapView( this);
  44. int position = getPosition(view);
  45. if (mOnViewPagerListener != null) {
  46. mOnViewPagerListener.onPageSelected(position, position == getItemCount() - 1);
  47. }
  48. // postion ---回调 ----》播放
  49. break;
  50. }
  51. super.onScrollStateChanged(state);
  52. }
  53. @Override
  54. public void onChildViewDetachedFromWindow(@NonNull View view) {
  55. //暂停播放操作
  56. if (mDrift >= 0) {
  57. if (mOnViewPagerListener != null)
  58. mOnViewPagerListener.onPageRelease( true, getPosition(view));
  59. } else {
  60. if (mOnViewPagerListener != null)
  61. mOnViewPagerListener.onPageRelease( false, getPosition(view));
  62. }
  63. }
  64. @Override
  65. public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
  66. this.mDrift = dy;
  67. return super.scrollVerticallyBy(dy, recycler, state);
  68. }
  69. @Override
  70. public boolean canScrollVertically() {
  71. return true;
  72. }
  73. }

3.接下来就是正常使用recycleview了


 
 
  1. import android.annotation.TargetApi;
  2. import android.content.Context;
  3. import android.media.MediaPlayer;
  4. import android.net.Uri;
  5. import android.os.Build;
  6. import android.os.Bundle;
  7. import android.support.v7.app.AppCompatActivity;
  8. import android.support.v7.widget.OrientationHelper;
  9. import android.support.v7.widget.RecyclerView;
  10. import android.util.Log;
  11. import android.view.LayoutInflater;
  12. import android.view.View;
  13. import android.view.ViewGroup;
  14. import android.widget.ImageView;
  15. import android.widget.RelativeLayout;
  16. import android.widget.VideoView;
  17. public class MainActivity extends AppCompatActivity {
  18. private static final String TAG = "douyin";
  19. private RecyclerView mRecyclerView;
  20. private MyAdapter mAdapter;
  21. MyLayoutManager2 myLayoutManager;
  22. @Override
  23. protected void onCreate(Bundle savedInstanceState) {
  24. super.onCreate(savedInstanceState);
  25. setContentView(R.layout.activity_main);
  26. initView();
  27. initListener();
  28. }
  29. private void initView() {
  30. mRecyclerView = findViewById(R.id.recycler);
  31. myLayoutManager = new MyLayoutManager2( this, OrientationHelper.VERTICAL, false);
  32. mAdapter = new MyAdapter( this);
  33. mRecyclerView.setLayoutManager(myLayoutManager);
  34. mRecyclerView.setAdapter(mAdapter);
  35. }
  36. private void initListener() {
  37. myLayoutManager.setOnViewPagerListener( new OnViewPagerListener() {
  38. @Override
  39. public void onInitComplete() {
  40. }
  41. @Override
  42. public void onPageRelease(boolean isNext, int position) {
  43. Log.e(TAG, "释放位置:" + position + " 下一页:" + isNext);
  44. int index = 0;
  45. if (isNext) {
  46. index = 0;
  47. } else {
  48. index = 1;
  49. }
  50. releaseVideo(index);
  51. }
  52. @Override
  53. public void onPageSelected(int position, boolean bottom) {
  54. Log.e(TAG, "选择位置:" + position + " 下一页:" + bottom);
  55. playVideo( 0);
  56. }
  57. });
  58. }
  59. class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
  60. private int[] imgs = {R.mipmap.img_video_1, R.mipmap.img_video_2, R.mipmap.img_video_3, R.mipmap.img_video_4, R.mipmap.img_video_5, R.mipmap.img_video_6, R.mipmap.img_video_7, R.mipmap.img_video_8};
  61. private int[] videos = {R.raw.video_1, R.raw.video_2, R.raw.video_3, R.raw.video_4, R.raw.video_5, R.raw.video_6, R.raw.video_7, R.raw.video_8};
  62. private int index = 0;
  63. private Context mContext;
  64. public MyAdapter(Context context) {
  65. this.mContext = context;
  66. }
  67. @Override
  68. public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
  69. View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view_pager, parent, false);
  70. return new ViewHolder(view);
  71. }
  72. @Override
  73. public void onBindViewHolder(ViewHolder holder, int position) {
  74. holder.img_thumb.setImageResource(imgs[index]);
  75. holder.videoView.setVideoURI(Uri.parse( "android.resource://" + getPackageName() + "/" + videos[index]));
  76. index++;
  77. if (index >= 7) {
  78. index = 0;
  79. }
  80. }
  81. @Override
  82. public int getItemCount() {
  83. return 88;
  84. }
  85. public class ViewHolder extends RecyclerView.ViewHolder {
  86. ImageView img_thumb;
  87. VideoView videoView;
  88. ImageView img_play;
  89. RelativeLayout rootView;
  90. public ViewHolder(View itemView) {
  91. super(itemView);
  92. img_thumb = itemView.findViewById(R.id.img_thumb);
  93. videoView = itemView.findViewById(R.id.video_view);
  94. img_play = itemView.findViewById(R.id.img_play);
  95. rootView = itemView.findViewById(R.id.root_view);
  96. }
  97. }
  98. }
  99. private void releaseVideo(int index) {
  100. View itemView = mRecyclerView.getChildAt(index);
  101. final VideoView videoView = itemView.findViewById(R.id.video_view);
  102. final ImageView imgThumb = itemView.findViewById(R.id.img_thumb);
  103. final ImageView imgPlay = itemView.findViewById(R.id.img_play);
  104. videoView.stopPlayback();
  105. imgThumb.animate().alpha( 1).start();
  106. imgPlay.animate().alpha( 0f).start();
  107. }
  108. @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
  109. private void playVideo(int position) {
  110. View itemView = mRecyclerView.getChildAt(position);
  111. final FullWindowVideoView videoView = itemView.findViewById(R.id.video_view);
  112. final ImageView imgPlay = itemView.findViewById(R.id.img_play);
  113. final ImageView imgThumb = itemView.findViewById(R.id.img_thumb);
  114. final RelativeLayout rootView = itemView.findViewById(R.id.root_view);
  115. final MediaPlayer[] mediaPlayer = new MediaPlayer[ 1];
  116. videoView.setOnPreparedListener( new MediaPlayer.OnPreparedListener() {
  117. @Override
  118. public void onPrepared(MediaPlayer mp) {
  119. }
  120. });
  121. videoView.setOnInfoListener( new MediaPlayer.OnInfoListener() {
  122. @Override
  123. public boolean onInfo(MediaPlayer mp, int what, int extra) {
  124. mediaPlayer[ 0] = mp;
  125. mp.setLooping( true);
  126. imgThumb.animate().alpha( 0).setDuration( 200).start();
  127. return false;
  128. }
  129. });
  130. videoView.start();
  131. imgPlay.setOnClickListener( new View.OnClickListener() {
  132. boolean isPlaying = true;
  133. @Override
  134. public void onClick(View v) {
  135. if (videoView.isPlaying()) {
  136. imgPlay.animate().alpha( 0.7f).start();
  137. videoView.pause();
  138. isPlaying = false;
  139. } else {
  140. imgPlay.animate().alpha( 0f).start();
  141. videoView.start();
  142. isPlaying = true;
  143. }
  144. }
  145. });
  146. }
  147. }

最后附上github地址

转自:https://blog.csdn.net/panghaha12138/article/details/84769026

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值