RecyclerView 的ViewPageLayoutManager

实现类似抖音的的全屏上下滑动翻页效果,方案有两种:

1.ViewPage

ViewPager来实现的时候,手机内存不够用的情况就会显现出来

2.RecyclerView

RecyclerView可以帮我们处理内存的回收和利用

实现过程:

1.自定义LayoutManager,并且继承LinearLayoutManager,这样就得到一个可以水平排向或者竖向排向的布局

PagerSnapHelper可以做到一次滑动翻一页,并且居中的viewpage效果

    public void onAttachedToWindow(RecyclerView view) {
        super.onAttachedToWindow(view);
        this.mPagerSnapHelper.attachToRecyclerView(view);
        this.mRecyclerView = view;
        this.mRecyclerView.addOnChildAttachStateChangeListener(this.mChildAttachStateChangeListener);
    }

2.开始播放和释放播放器的时机

重写onScrollStateChanged()函数,这里面有三种状态:

 

  • SCROLL_STATE_IDLE(空闲)

  • SCROLL_STATE_DRAGGING(拖动)

  • SCROLL_STATE_SETTLING(要移动到最后位置时)

我们需要的就是RecyclerView停止时的状态,我们就可以拿到这个View的Position.注意这里还有一个问题,当你通过这个position去拿Item会报错。打印Log,你会发现RecyclerView.getChildCount()一直为1或者会出现为2的情况。好了,我们自己来实现一个接口然后通过接口把状态传递出去。

翻页状态监听器:

public interface OnViewPagerListener {
    void onInitComplete();

    void onPageRelease(boolean var1, int var2);

    void onPageSelected(int var1, boolean var2);
}

重写LinearLayoutManager的onScrollStateChanged方法:

    public void onScrollStateChanged(int state) {
        switch(state) {
        case 0:
            View viewIdle = this.mPagerSnapHelper.findSnapView(this);
            int positionIdle = this.getPosition(viewIdle);
            if (this.mOnViewPagerListener != null && this.getChildCount() == 1) {
                this.mOnViewPagerListener.onPageSelected(positionIdle, positionIdle == this.getItemCount() - 1);
            }
            break;
        case 1:
            View viewDrag = this.mPagerSnapHelper.findSnapView(this);
            this.getPosition(viewDrag);
            break;
        case 2:
            View viewSettling = this.mPagerSnapHelper.findSnapView(this);
            this.getPosition(viewSettling);
        }

    }

3. 区分上一页还是下一页

列表的选中监听好了,我们就看看什么时候释放视频的资源,第二步中的三种状态,去打印getChildCount()的日志,你会发现getChildCount()在:

SCROLL_STATE_DRAGGING会为1

SCROLL_STATE_SETTLING为2

SCROLL_STATE_IDLE有时为1,有时为2
我们要做的是要知道在什么时候去做释放视频的操作,还要分清是释放上一页还是下一页,因为适配器adapter的position在这里不好使嘛,这里有两个方法scrollHorizontallyBy()和scrollVerticallyBy()可以拿到滑动偏移量,可以判断滑动方向

    public int scrollVerticallyBy(int dy, Recycler recycler, State state) {
        this.mDrift = dy;
        return super.scrollVerticallyBy(dy, recycler, state);
    }

    public int scrollHorizontallyBy(int dx, Recycler recycler, State state) {
        this.mDrift = dx;
        return super.scrollHorizontallyBy(dx, recycler, state);
    }
    private OnChildAttachStateChangeListener mChildAttachStateChangeListener = new OnChildAttachStateChangeListener() {
        public void onChildViewAttachedToWindow(View view) {
            if (ViewPagerLayoutManager.this.mOnViewPagerListener != null && ViewPagerLayoutManager.this.getChildCount() == 1) {
                ViewPagerLayoutManager.this.mOnViewPagerListener.onInitComplete();
            }

        }

        public void onChildViewDetachedFromWindow(View view) {
            if (ViewPagerLayoutManager.this.mDrift >= 0) {
                if (ViewPagerLayoutManager.this.mOnViewPagerListener != null) {
                    ViewPagerLayoutManager.this.mOnViewPagerListener.onPageRelease(true, ViewPagerLayoutManager.this.getPosition(view));
                }
            } else if (ViewPagerLayoutManager.this.mOnViewPagerListener != null) {
                ViewPagerLayoutManager.this.mOnViewPagerListener.onPageRelease(false, ViewPagerLayoutManager.this.getPosition(view));
            }

        }
    };

完整代码:

ViewPageLayoutManager:

public class ViewPagerLayoutManager extends LinearLayoutManager {
    private static final String TAG = "ViewPagerLayoutManager";
    private PagerSnapHelper mPagerSnapHelper;
    private OnViewPagerListener mOnViewPagerListener;
    private RecyclerView mRecyclerView;
    private int mDrift;
    private OnChildAttachStateChangeListener mChildAttachStateChangeListener = new OnChildAttachStateChangeListener() {
        public void onChildViewAttachedToWindow(View view) {
            if (ViewPagerLayoutManager.this.mOnViewPagerListener != null && ViewPagerLayoutManager.this.getChildCount() == 1) {
                ViewPagerLayoutManager.this.mOnViewPagerListener.onInitComplete();
            }

        }

        public void onChildViewDetachedFromWindow(View view) {
            if (ViewPagerLayoutManager.this.mDrift >= 0) {
                if (ViewPagerLayoutManager.this.mOnViewPagerListener != null) {
                    ViewPagerLayoutManager.this.mOnViewPagerListener.onPageRelease(true, ViewPagerLayoutManager.this.getPosition(view));
                }
            } else if (ViewPagerLayoutManager.this.mOnViewPagerListener != null) {
                ViewPagerLayoutManager.this.mOnViewPagerListener.onPageRelease(false, ViewPagerLayoutManager.this.getPosition(view));
            }

        }
    };

    public ViewPagerLayoutManager(Context context, int orientation) {
        super(context, orientation, false);
        this.init();
    }

    public ViewPagerLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
        this.init();
    }

    private void init() {
        this.mPagerSnapHelper = new PagerSnapHelper();
    }

    public void onAttachedToWindow(RecyclerView view) {
        super.onAttachedToWindow(view);
        this.mPagerSnapHelper.attachToRecyclerView(view);
        this.mRecyclerView = view;
        this.mRecyclerView.addOnChildAttachStateChangeListener(this.mChildAttachStateChangeListener);
    }

    public void onLayoutChildren(Recycler recycler, State state) {
        super.onLayoutChildren(recycler, state);
    }

    public void onScrollStateChanged(int state) {
        switch(state) {
        case 0:
            View viewIdle = this.mPagerSnapHelper.findSnapView(this);
            int positionIdle = this.getPosition(viewIdle);
            if (this.mOnViewPagerListener != null && this.getChildCount() == 1) {
                this.mOnViewPagerListener.onPageSelected(positionIdle, positionIdle == this.getItemCount() - 1);
            }
            break;
        case 1:
            View viewDrag = this.mPagerSnapHelper.findSnapView(this);
            this.getPosition(viewDrag);
            break;
        case 2:
            View viewSettling = this.mPagerSnapHelper.findSnapView(this);
            this.getPosition(viewSettling);
        }

    }

    public int scrollVerticallyBy(int dy, Recycler recycler, State state) {
        this.mDrift = dy;
        return super.scrollVerticallyBy(dy, recycler, state);
    }

    public int scrollHorizontallyBy(int dx, Recycler recycler, State state) {
        this.mDrift = dx;
        return super.scrollHorizontallyBy(dx, recycler, state);
    }

    public void setOnViewPagerListener(OnViewPagerListener listener) {
        this.mOnViewPagerListener = listener;
    }
}

主Activity:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "ViewPagerActivity";
    private RecyclerView mRecyclerView;
    private MyAdapter mAdapter;
    private ViewPagerLayoutManager mLayoutManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();

        initListener();
    }

    private void initView() {
        mRecyclerView = findViewById(R.id.recycler);

        mLayoutManager = new ViewPagerLayoutManager(this, OrientationHelper.VERTICAL);
        mAdapter = new MyAdapter();
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setAdapter(mAdapter);
    }

    private void initListener(){
        mLayoutManager.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 isBottom) {
                Log.e(TAG,"选中位置:"+position+"  是否是滑动到底部:"+isBottom);
                playVideo(0);
            }


            public void onLayoutComplete() {
                playVideo(0);
            }

        });
    }

    private void playVideo(int position) {
        View itemView = mRecyclerView.getChildAt(0);
        final VideoView 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.start();
        videoView.setOnInfoListener(new MediaPlayer.OnInfoListener() {
            @Override
            public boolean onInfo(MediaPlayer mp, int what, int extra) {
                mediaPlayer[0] = mp;
                Log.e(TAG,"onInfo");
                mp.setLooping(true);
                imgThumb.animate().alpha(0).setDuration(200).start();
                return false;
            }
        });
        videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                Log.e(TAG,"onPrepared");

            }
        });


        imgPlay.setOnClickListener(new View.OnClickListener() {
            boolean isPlaying = true;
            @Override
            public void onClick(View v) {
                if (videoView.isPlaying()){
                    Log.e(TAG,"isPlaying:"+videoView.isPlaying());
                    imgPlay.animate().alpha(1f).start();
                    videoView.pause();
                    isPlaying = false;
                }else {
                    Log.e(TAG,"isPlaying:"+videoView.isPlaying());
                    imgPlay.animate().alpha(0f).start();
                    videoView.start();
                    isPlaying = true;
                }
            }
        });
    }

    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();
    }


    class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{
        private int[] imgs = {R.mipmap.video11,R.mipmap.video12,R.mipmap.video13,R.mipmap.video14,R.mipmap.img_video_2};
        private int[] videos = {R.raw.video11,R.raw.video12,R.raw.video13,R.raw.video14,R.raw.video_2};
        public MyAdapter(){
        }


        @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[position%5]);



            holder.videoView.setVideoURI(Uri.parse("android.resource://"+getPackageName()+"/"+ videos[position%5]));
        }

        @Override
        public int getItemCount() {
            return 50;
        }

        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);
            }
        }
    }
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RecyclerView 嵌套 RecyclerView 可以用来实现一些复杂的列表布局,比如类似于网格布局的效果。实现的方法可以分为两种:使用 RecyclerView.Adapter 实现和使用 RecyclerView.LayoutManager 实现。 1. 使用 RecyclerView.Adapter 实现 在外层 RecyclerView 的 Adapter 中,需要将内层 RecyclerView 的 Adapter 一并传递进去,同时需要重写 onBindViewHolder 方法,将内层 RecyclerView 的 Adapter 绑定到内层 RecyclerView 上。 ```java public class OuterAdapter extends RecyclerView.Adapter<OuterAdapter.OuterViewHolder> { private List<InnerAdapter> innerAdapters; public void setInnerAdapters(List<InnerAdapter> innerAdapters) { this.innerAdapters = innerAdapters; } @NonNull @Override public OuterViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_outer, parent, false); return new OuterViewHolder(view); } @Override public void onBindViewHolder(@NonNull OuterViewHolder holder, int position) { holder.innerRecyclerView.setAdapter(innerAdapters.get(position)); } @Override public int getItemCount() { return innerAdapters.size(); } static class OuterViewHolder extends RecyclerView.ViewHolder { RecyclerView innerRecyclerView; public OuterViewHolder(@NonNull View itemView) { super(itemView); innerRecyclerView = itemView.findViewById(R.id.inner_recycler_view); innerRecyclerView.setLayoutManager(new LinearLayoutManager(itemView.getContext(), RecyclerView.HORIZONTAL, false)); } } } ``` 在内层 RecyclerView 的 Adapter 中,需要重写 onCreateViewHolder 方法,创建内层 RecyclerView 的 ViewHolder,同时需要重写 onBindViewHolder 方法,将数据绑定到内层 RecyclerView 的 ViewHolder 上。 ```java public class InnerAdapter extends RecyclerView.Adapter<InnerAdapter.InnerViewHolder> { private List<String> data; public void setData(List<String> data) { this.data = data; } @NonNull @Override public InnerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_inner, parent, false); return new InnerViewHolder(view); } @Override public void onBindViewHolder(@NonNull InnerViewHolder holder, int position) { holder.textView.setText(data.get(position)); } @Override public int getItemCount() { return data.size(); } static class InnerViewHolder extends RecyclerView.ViewHolder { TextView textView; public InnerViewHolder(@NonNull View itemView) { super(itemView); textView = itemView.findViewById(R.id.text_view); } } } ``` 2. 使用 RecyclerView.LayoutManager 实现 在外层 RecyclerView 的 Adapter 中,需要将内层 RecyclerView 的 LayoutManager 一并传递进去,同时需要重写 onBindViewHolder 方法,将内层 RecyclerView 的 LayoutManager 绑定到内层 RecyclerView 上。 ```java public class OuterAdapter extends RecyclerView.Adapter<OuterAdapter.OuterViewHolder> { private List<InnerLayoutManager> innerLayoutManagers; public void setInnerLayoutManagers(List<InnerLayoutManager> innerLayoutManagers) { this.innerLayoutManagers = innerLayoutManagers; } @NonNull @Override public OuterViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_outer, parent, false); return new OuterViewHolder(view); } @Override public void onBindViewHolder(@NonNull OuterViewHolder holder, int position) { holder.innerRecyclerView.setLayoutManager(innerLayoutManagers.get(position)); } @Override public int getItemCount() { return innerLayoutManagers.size(); } static class OuterViewHolder extends RecyclerView.ViewHolder { RecyclerView innerRecyclerView; public OuterViewHolder(@NonNull View itemView) { super(itemView); innerRecyclerView = itemView.findViewById(R.id.inner_recycler_view); } } } ``` 在内层 RecyclerView 的 LayoutManager 中,需要重写 generateDefaultLayoutParams 方法,设置内层 RecyclerView 的布局参数,同时需要重写 canScrollHorizontally 和 canScrollVertically 方法,判断内层 RecyclerView 是否可以滑动。 ```java public class InnerLayoutManager extends LinearLayoutManager { public InnerLayoutManager(Context context) { super(context); } @Override public RecyclerView.LayoutParams generateDefaultLayoutParams() { return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); } @Override public boolean canScrollHorizontally() { return false; } @Override public boolean canScrollVertically() { return false; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值