不少朋友对短视频,上下滑动播放视频效果比较比较感兴趣,今天看看这个案例。
1、效果图:
讲下大概思路,使用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的详解
2、正式撸代码: 1.首先定义一个接口,用来执行item的相关操作
public interface OnViewPagerListener { /*初始化完成*/ void onInitComplete(); /*释放的监听*/ void onPageRelease(boolean isNext, int position); /*选中的监听以及判断是否滑动到底部*/ void onPageSelected(int position, boolean isBottom); }
2.继承LinearLayoutManager ,对滑入滑出的item回调1中接口里面的方法
import android.content.Context; import android.support.annotation.NonNull; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.PagerSnapHelper; import android.support.v7.widget.RecyclerView; import android.view.View; public class MyLayoutManager extends LinearLayoutManager implements RecyclerView.OnChildAttachStateChangeListener { private int mDrift;//位移,用来判断移动方向 private PagerSnapHelper mPagerSnapHelper; private OnViewPagerListener mOnViewPagerListener; public MyLayoutManager(Context context) { super(context); } public MyLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); mPagerSnapHelper = new PagerSnapHelper(); } @Override public void onAttachedToWindow(RecyclerView view) { view.addOnChildAttachStateChangeListener(this); mPagerSnapHelper.attachToRecyclerView(view); super.onAttachedToWindow(view); } //当Item添加进来了 调用这个方法 // @Override public void onChildViewAttachedToWindow(@NonNull View view) { // 播放视频操作 即将要播放的是上一个视频 还是下一个视频 int position = getPosition(view); if (0 == position) { if (mOnViewPagerListener != null) { mOnViewPagerListener.onPageSelected(getPosition(view), false); } } } public void setOnViewPagerListener(OnViewPagerListener mOnViewPagerListener) { this.mOnViewPagerListener = mOnViewPagerListener; } @Override public void onScrollStateChanged(int state) { switch (state) { case RecyclerView.SCROLL_STATE_IDLE: View view = mPagerSnapHelper.findSnapView(this); int position = getPosition(view); if (mOnViewPagerListener != null) { mOnViewPagerListener.onPageSelected(position, position == getItemCount() - 1); } // postion ---回调 ----》播放 break; } super.onScrollStateChanged(state); } @Override public void onChildViewDetachedFromWindow(@NonNull View view) { //暂停播放操作 if (mDrift >= 0) { if (mOnViewPagerListener != null) mOnViewPagerListener.onPageRelease(true, getPosition(view)); } else { if (mOnViewPagerListener != null) mOnViewPagerListener.onPageRelease(false, getPosition(view)); } } @Override public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { this.mDrift = dy; return super.scrollVerticallyBy(dy, recycler, state); } @Override public boolean canScrollVertically() { return true; } }
3.接下来就是正常使用recycleview了 配合原生VideoView 播放视频,切换时先用一张截图盖住视频,视频渲染成功再隐藏截图,感觉上是无缝切换(这里是原生播放器初始加载视频会黑屏,如果用更高级的播放器可能不会有这个问题)
import android.annotation.TargetApi; import android.content.Context; import android.media.MediaPlayer; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.OrientationHelper; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.VideoView; public class MainActivity extends AppCompatActivity { private static final String TAG = "douyin"; private RecyclerView mRecyclerView; private MyAdapter mAdapter; MyLayoutManager2 myLayoutManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initListener(); } private void initView() { mRecyclerView = findViewById(R.id.recycler); myLayoutManager = new MyLayoutManager2(this, OrientationHelper.VERTICAL, false); mAdapter = new MyAdapter(this); mRecyclerView.setLayoutManager(myLayoutManager); mRecyclerView.setAdapter(mAdapter); } private void initListener() { myLayoutManager.setOnViewPagerListener(new OnViewPagerListener() { @Override public void onInitComplete() { } @Override public void onPageRelease(boolean isNext, int position) { Log.e(TAG, "释放位置:" + position + " 下一页:" + isNext); int index = 0; if (isNext) { index = 0; } else { index = 1; } releaseVideo(index); } @Override public void onPageSelected(int position, boolean bottom) { Log.e(TAG, "选择位置:" + position + " 下一页:" + bottom); playVideo(0); } }); } class MyAdapter extends RecyclerView.Adapter { 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}; 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}; private int index = 0; private Context mContext; public MyAdapter(Context context) { this.mContext = context; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view_pager, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.img_thumb.setImageResource(imgs[index]); holder.videoView.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + videos[index])); index++; if (index >= 7) { index = 0; } } @Override public int getItemCount() { return 88; } public class ViewHolder extends RecyclerView.ViewHolder { ImageView img_thumb; VideoView videoView; ImageView img_play; RelativeLayout rootView; public ViewHolder(View itemView) { super(itemView); img_thumb = itemView.findViewById(R.id.img_thumb); videoView = itemView.findViewById(R.id.video_view); img_play = itemView.findViewById(R.id.img_play); rootView = itemView.findViewById(R.id.root_view); } } } private void releaseVideo(int index) { View itemView = mRecyclerView.getChildAt(index); final VideoView videoView = itemView.findViewById(R.id.video_view); final ImageView imgThumb = itemView.findViewById(R.id.img_thumb); final ImageView imgPlay = itemView.findViewById(R.id.img_play); videoView.stopPlayback(); imgThumb.animate().alpha(1).start(); imgPlay.animate().alpha(0f).start(); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) private void playVideo(int position) { View itemView = mRecyclerView.getChildAt(position); final FullWindowVideoView videoView = itemView.findViewById(R.id.video_view); final ImageView imgPlay = itemView.findViewById(R.id.img_play); final ImageView imgThumb = itemView.findViewById(R.id.img_thumb); final RelativeLayout rootView = itemView.findViewById(R.id.root_view); final MediaPlayer[] mediaPlayer = new MediaPlayer[1]; videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { } }); videoView.setOnInfoListener(new MediaPlayer.OnInfoListener() { @Override public boolean onInfo(MediaPlayer mp, int what, int extra) { mediaPlayer[0] = mp; mp.setLooping(true); imgThumb.animate().alpha(0).setDuration(200).start(); return false; } }); videoView.start(); imgPlay.setOnClickListener(new View.OnClickListener() { boolean isPlaying = true; @Override public void onClick(View v) { if (videoView.isPlaying()) { imgPlay.animate().alpha(0.7f).start(); videoView.pause(); isPlaying = false; } else { imgPlay.animate().alpha(0f).start(); videoView.start(); isPlaying = true; } } }); } }
最后附上github地址,点击《阅读原文》
原创作者:庞哈哈哈12138,原文:https://www.jianshu.com/p/3a043cd4eb1f