imcys.com
遵从中二的召唤,来吧少年!

【笔记】实现仿抖音视频滑动RecyclerView+PagerSnapHelper

前言

起因

嗯。。。。这篇博文是在参加字节跳动青训营安卓基础班课程前写的,其实也能反映出我比较慌,主要是基础的东西不过关,比较担心后面的情况。所以这两天先看了一下,毕竟写过BILIBILIAS,还是有点用的。这篇博文写下也就是去给自己留个印象,归纳一下这两天的成果吧。

界面实现

我们来看看这个界面,它采用的是,ViewPager2 + Fragment 的方式实现4个页面,当然这个不是重点,就是做了个测试,来确定这种方案是否可行。

实现视频展示

这个抖音的展示是垂直滑动视频,来进行切换的,其实我当时考虑到的是可能有专门的控件,结果是我想多了,没有,无奈我去网上查了下,发现可以利用RecyclerView来做。接下来,根据网上各种资料,成功实现了,下面我来讲讲我的理解和实现。

利用RecyclerView+PagerSnapHelper实现滚动效果

首先我们要知道,RecyclerView可以去自定义布局,提供滚动,但是Item做到占满一页真的没做过,也不知道如何实现,这个时间我了解到了PagerSnapHelper

PagerSnapHelperSnapHelper的一个子类,让RecyclerView具备ViewPage的翻页功能,同时也具有Item居中功能,作为初学者去深究PagerSnapHelper怎么实现的显然不太现实,如果看文章的是位大佬,或者对自己的安卓功底有信心,可以去网上看看其他人的解释或者说源代码。

简单的看一下流程吧,不然用着也有点慌。

PagerSnapHelper继承自SnapHelper,而SnapHelper又继承了RecyclerViewOnFlingListener,顾名思义(哈哈,我英语很差的啦,翻译了一下)这是Fling的监听器,那么Fling是个什么东西?哈哈,往下看我也就不明白了,从这个抽象类的注释来看,这个它与滚动有关系,这也是能控制RecyclerViewItem的原因吧,有兴趣了自己看看,我就不深究了,目前的水平有限,以后来填坑。

OK,简单来讲,PagerSnapHelper和绑定RecyclerView后,就可以实现ViewPage独立翻页和吸附功能。

下面我们来看看代码

RecyclerView recyclerView = rootView.findViewById(R.id.Home_RecyclerView);
snapHelper = new PagerSnapHelper();
//附着recyclerView
snapHelper.attachToRecyclerView(recyclerView);

这是在fragment里写的,所以有rootView(可能是多余的话哈哈)

那么有了这个之后的话就写adapter吧,RecyclerView的适配器我就不多说了吧,不是今天的主角,我贴下代码。

不知道大家注意到没有,这个Adapter的ViewHolder是用public修饰的,这个我们后面来看看用处。

public class MyVideoAdapter extends RecyclerView.Adapter<MyVideoAdapter.ViewHolder> {

    private List<Video> mData;
    private Context mContext;
    private ViewHolder holder;
    private View rootView;


    public MyVideoAdapter(List<Video> mData, Context context) {
        this.mData = mData;
        this.mContext = context;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {


        rootView = LayoutInflater.from(mContext).inflate(R.layout.item_home_video, parent, false);

        holder = new ViewHolder(rootView);

        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {

        JZDataSource jzDataSource = new JZDataSource(mData.get(position).getVideoUrl(), "我的杰酱不可能那么可爱");
        holder.jzPlay.setUp(jzDataSource, JzvdStd.SCREEN_NORMAL);
        if (position == 0) {
            holder.jzPlay.startVideo();
        }

    }


    @Override
    public int getItemCount() {
        return mData.size();
    }


    public static class ViewHolder extends RecyclerView.ViewHolder {
        public View rootView;
        public JZPlay jzPlay;

        public ViewHolder(View view) {
            super(view);
            rootView = view;
            jzPlay = view.findViewById(R.id.Home_Item_JzvdStd);
        }

    }
}

还没有结束,我们还需要一个东西,设置下垂直滚动,这个是我们需要的效果,当然你可以改这里为其他的方式看看,不拘泥于垂直。

layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);

//让recyclerView是垂直滚动
recyclerView.setLayoutManager(layoutManager);

到这里,运行一下,你的Item就是垂直的,而且是一屏一个,垂直滑动加载下一个,具备垂直效果。但是这仅仅是解决了展示性的问题,现在得把视频加进去。

在上面的代码我没有说到播放器的事情,其实适配器里已经有了呢。

下面我介绍我使用的播放器——饺子播放器,BILIBILIAS的播放器就是它。

如果按照上面的方式,把饺子播放器放入item里,仅仅是做到了视频插入,但是抖音是有自动播放的,这个怎么办?下面我在网上也找到了一个解决方案。

RecyclerView有一个方法addOnScrollListener是滚动监听器,需要实现抽象类两个的方法,其中一个onScrollStateChanged,就是我们需要的了。

 //监听滚动
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                switch (newState) {
                    case RecyclerView.SCROLL_STATE_IDLE://停止滚动
                        //获取snapHelper的布局
                        View view = snapHelper.findSnapView(layoutManager);

                        //获取当前item
                        int position = recyclerView.getChildAdapterPosition(view);

                        if (currentPosition != position) {
                            //如果当前position 和 上一次固定后的position 相同, 说明是同一个, 只不过滑动了一点点, 然后又释放了
                            JZPlay.releaseAllVideos(); //关闭之前的视频

                            RecyclerView.ViewHolder viewHolder = recyclerView.getChildViewHolder(view);

                            //判断获取到了而且是适配的数据对象
                            if (viewHolder != null && viewHolder instanceof MyVideoAdapter.ViewHolder) {
                                //播放视频
                                ((MyVideoAdapter.ViewHolder) viewHolder).jzPlay.startVideo();
                            }
                        }
                        currentPosition = position;

                        break;
                    case RecyclerView.SCROLL_STATE_DRAGGING://拖动
                        break;
                    case RecyclerView.SCROLL_STATE_SETTLING://惯性滑动
                        break;
                }
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
            }
        });

我们看看上面代码,当滚动状态改变时,就会调用onScrollStateChanged,此时传入了newState,这个就是滚动状态。都有注释,根据item的下标来确定是否有变动。之前说ViewHolder需要public,现在我们可以发现这是为了我们去在这里使用,以此获取到当前item的ViewHolder,再通过ViewHolder来设置饺子播放器的播放状态。当切换后就将饺子播放器关闭,然后再播放当前页面的视频。

当然,这样的写法是不全面的,我们知道抖音打开是会自动播放视频的,那么现在我们回头看看适配器,有一则判断,如果判断是0,也就是第一个视频,那么就播放它。

至于切换,我们需要在生命周期里添加一下。

@Override
public void onPause() {
        super.onPause();
        JZPlay.releaseAllVideos();
    }

当fragment切换不可见时会执行它关闭视频。

饺子播放器继承自定义点击效果

饺子播放器固然强大,但是它是为了播放视频而设计的,像我们这样的就需要自定义一下,比如在视频播放时,点击后暂停视频,这个是我们需要额外实现的。

当然,今晚太晚了,我就不写具体实现了,下来我把他补上,我也是刚刚自己实现了这个继承的点击效果,还是比较不错的,但是仅仅如此是不足的,等我搞定了再补充。

感谢大家看到这里

萌新杰少

文章作者

I im CYS,一个热爱二次元的大专开发者

发表回复

textsms
account_circle
email

Captcha Code

萌新杰少の秘密基地

【笔记】实现仿抖音视频滑动RecyclerView+PagerSnapHelper
利用RecyclerView+PagerSnapHelper实现滚动效果
扫描二维码继续阅读
2022-07-25