太多朋友对短视频,上下滚动播放视频效果比较比较研究,今天看看这个案例。
讲下大概思路,使用Recycleview配合自定义LinearLayoutManager来实现这个功能,这里着重说下自定义LinearLayoutManager的实现可以看到每当下一个项目滑入屏幕时,上面的项目会继续播放视频,而滑入的项目只有当全部进入屏幕才会播放,而且当手指抬起时,当前item会根据滑动的距离相应的自动滑入滑出,针对这种情况,就会想到使用SnapHelper
RecyclerView在24.2.0版本中新增了SnapHelper这个辅助类,利用辅助RecyclerView在滚动结束时将项目对准到某个位置。特别是列表横向滑动时,很多时候不会让列表滑到任意位置,甚至会有一定的规则限制,这时候就可以通过SnapHelper来定义对齐规则了。
SnapHelper是一个抽象类,官方提供了一个LinearSnapHelper的子类,可以让RecyclerView滚动停止时相应的项保持中间位置。25.1.0版本中官方又提供了一个PagerSnapHelper的子类,可以使RecyclerView像ViewPager一样效果,一次只能滑动一页,而且居中显示,直接使用SnapHelper可以帮助RecyclerView滑动完成后进行对齐操作,让item的侧边对齐或者居中对齐,这样实现上下滑动进行视频切换。这里有SnapHelper的详解
2,正式撸代码:1。首先定义一个接口,用于执行item的相关操作
公共接口OnViewPagerListener {
/ * 初始化完成* /
void onInitComplete();
/ *释放的监听器* /
void onPageRelease(boolean isNext,int position);
/ *的监听器以及判断是否可以滑动到底部* /
void onPageSelected(int position,boolean isBottom);
} ```
2.继承LinearLayoutManager,对滑入滑出的项目某些1中接口里面的方法
导入android.content.Context; 导入android.support.annotation.NonNull; 导入android.support.v7.widget.LinearLayoutManager; 导入android.support.v7.widget.PagerSnapHelper; 导入android.support.v7.widget.RecyclerView; 导入android.view.View;
公共类MyLayoutManager扩展LinearLayoutManager实现RecyclerView.OnChildAttachStateChangeListener {private int mDrift;//位移,用于判断移动方向的专有PagerSnapHelper mPagerSnapHelper;私人OnViewPagerListener mOnViewPagerListener;公共MyLayoutManager(上下文上下文){super(context);} public MyLayoutManager(上下文上下文,int方向,布尔反向布局){超级(上下文,方向,reverseLayout);mPagerSnapHelper = new PagerSnapHelper();} @覆盖公共无效onAttachedToWindow(RecyclerView视图){view.addOnChildAttachStateChangeListener(本);
mPagerSnapHelper.attachToRecyclerView(view);
super.onAttachedToWindow(view);
}
//当项目添加进来了调用这个方法// @覆盖公共无效onChildViewAttachedToWindow(@NonNull查看视图){
//播放视频操作即将要播放的是上一个视频还是下一个视频int position = getPosition(view);if(0 ==位置){if(mOnViewPagerListener!= null){mOnViewPagerListener.onPageSelected(getPosition(view),false);}}}} public void setOnViewPagerListener(OnViewPagerListener mOnViewPagerListener){this.mOnViewPagerListener = mOnViewPagerListener;} @覆盖公共无效onScrollStateChanged(INT状态){开关(状态){情况下RecyclerView.SCROLL_STATE_IDLE:Viewview = mPagerSnapHelper.findSnapView(本); int position = getPosition(view);如果(mOnViewPagerListener!= null){mOnViewPagerListener.onPageSelected(position,position == getItemCount()-1);}
//位置—部分----》播放break;} super.onScrollStateChanged(状态);} @覆盖公共无效onChildViewDetachedFromWindow(@NonNull视图视图){
//暂停播放操作
if(mDrift> = 0){
if(mOnViewPagerListener!= null)
mOnViewPagerListener.onPageRelease(true,getPosition(view));
} else {
如果(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 播放视频,切换时先用一张截图盖住视频,视频渲染成功再隐藏截图,感觉上是无缝切换(这里是原生播放器初始加载视频会黑屏,如果用更高级的播放器可能不会有这个问题)
导入android.annotation.TargetApi; 导入android.content.Context; 导入android.media.MediaPlayer; 导入android.net.Uri; 导入android.os.Build; 导入android.os.Bundle; 导入android.support.v7.app.AppCompatActivity; 导入android.support.v7.widget.OrientationHelper; 导入android.support.v7.widget.RecyclerView; 导入android.util.Log; 导入android.view.LayoutInflater; 导入android.view.View; 导入android.view.ViewGroup; 导入android.widget.ImageView; 导入android.widget.RelativeLayout; 导入android.widget.VideoView;
公共类MainActivity扩展了AppCompatActivity {private static final String TAG =“ douyin”; 私人RecyclerView mRecyclerView; 私有MyAdapter mAdapter; MyLayoutManager2 myLayoutManager; @Override protected void onCreate(捆绑的saveInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();initListener();}私有无效initView(){mRecyclerView = findViewById(R.id.recycler);myLayoutManager = new MyLayoutManager2(this,OrientationHelper.VERTICAL,false);mAdapter =新的MyAdapter(this); mRecyclerView.setLayoutManager(myLayoutManager); mRecyclerView.setAdapter(mAdapter); } private void initListener(){
myLayoutManager.setOnViewPagerListener(new OnViewPagerListener() {
@Override
public void onInitComplete() {
}
@覆盖
公共无效onPageRelease(布尔isNext,INT位置){
Log.e(TAG, “释放位置:” +位置+ “下一页:” + isNext);
int索引= 0;
如果(isNext){
索引= 0;
} else {
index = 1;
}
releaseVideo(index);
}
@覆盖
公共无效使用onPageSelected(INT位置,布尔底部){
Log.e(TAG, “选择位置:” +位置+ “下一页:” +底部);
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;
公共ViewHolder(查看itemView){
超级(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索引){
查看itemView = mRecyclerView.getChildAt(索引);
最终VideoView videoView = itemView.findViewById(R.id.video_view);
最终的ImageView imgThumb = itemView.findViewById(R.id.img_thumb);
最终的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)私有无效playVideo(int position){查看itemView = mRecyclerView.getChildAt(position);最终FullWindowVideoView videoView = itemView.findViewById(R.id.video_view);最终的ImageView imgPlay = itemView.findViewById(R.id.img_play); 最终的ImageView imgThumb = itemView.findViewById(R.id.img_thumb); 最终RelativeLayout rootView = itemView.findViewById(R.id.root_view);最终的MediaPlayer [] mediaPlayer =新的MediaPlayer [1]; videoView.setOnPreparedListener(新MediaPlayer.OnPreparedListener(){ @ 覆盖公共无效onPrepared(MediaPlayer的熔点){ } }); videoView.setOnInfoListener(新MediaPlayer.OnInfoListener(){ @
覆盖公共布尔onInfo(MediaPlayer的浓度,INT,整型附加){
MEDIAPLAYER [0] =熔点;
mp.setLooping(真)
。imgThumb.animate()α(0).setDuration(200)。开始();
返回假
}
});
videoView.start();
imgPlay.setOnClickListener(新View.OnClickListener(){
boolean isPlaying = true;)。)。 )。))))))))))))))))。)
@覆盖
公共无效的onClick(查看v){
如果(videoView.isPlaying()){
imgPlay.animate()α(0.7F) 。
;;;; videoView .pause();
IsPlaying模块= FALSE;
}其他{
imgPlay.animate()。alpha(0f)
.start(); videoView.start();
isPlaying = true;
}
}
} ;;
}}”