Android Recyclerview列表自动播放视频

来源:互联网 发布:底盘装甲 知乎 编辑:程序博客网 时间:2024/06/08 14:13

前言:最近项目比较忙很久没写博客了,一个月迭代了三个版本也是醉了。。。谁叫我们是苦逼的程序猿呢,回归正传;最近主要在弄一个跟视频有关的项目,里面也学到一些东西,现在记录一下;其中一个是仿微博的视频列表自动播放功能,具体可以看下图:

这里写图片描述

项目中视频使用的是GSYVideoPlayer 这个开源库。
ps:作者很热心,nice。

废话不多说,直接进入重点;既然要实现类似微博那种滚动列表时,处于当前屏幕的项自动播放,那么肯定得监听列表的滚动事件,好在Recyclerview中给我们提供了接口:

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {            @Override            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {                super.onScrollStateChanged(recyclerView, newState);                switch (newState) {                    case SCROLL_STATE_IDLE: //滚动停止                        break;                    case SCROLL_STATE_DRAGGING: //手指拖动                        break;                    case SCROLL_STATE_SETTLING: //惯性滚动                        break;                }            }           @Override            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {                super.onScrolled(recyclerView, dx, dy);            }        });

如上onScrollStateChanged 方法 给我们返回了三种状态:
SCROLL_STATE_DRAGGING: 手指按住屏幕拖动
SCROLL_STATE_SETTLING: 手指快速在屏幕滑一下后的惯性滑动
SCROLL_STATE_IDLE: 屏幕处于禁止状态

onScrolled 方法给我们返回了 dx:水平滚动距离、dy:垂直滚动距离。这两个值都是用手指开始触摸的位置减去移动后的位置,所以:
dx > 0 时为手指向左滚动,列表滚动显示右面的内容
dx < 0 时为手指向右滚动,列表滚动显示左面的内容
dy > 0 时为手指向上滚动,列表滚动显示下面的内容
dy < 0 时为手指向下滚动,列表滚动显示上面的内容
项目中暂时没用到这些,但是这些值很有用。

在这个方法中我们需要获取三个值:
(1) 在屏幕可见区域的第一项位置 - 通过findFirstVisibleItemPosition()方法获取
(2) 在屏幕可见区域的最后一项位置 - 通过findLastVisibleItemPosition() 方法获取
(3)屏幕可见项的数目 - 用(2)减去(1)即可

为什么需要以上值,这里说下整体思路:
(1)获取当前处于屏幕可见的列表
(2)滑出屏幕的视频我们需要回收掉
(3)当屏幕处于静止状态时我们才开始播放视频

第一点:获取可见列表;上面获取的三个值已经解决了,直接看代码:

        public int firstVisibleItem, lastVisibleItem, visibleCount;             @Override            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {                super.onScrolled(recyclerView, dx, dy);                firstVisibleItem = layoutManager.findFirstVisibleItemPosition();                lastVisibleItem = layoutManager.findLastVisibleItemPosition();                visibleCount = lastVisibleItem - firstVisibleItem;            }

第二点:回收滑出屏幕的视频,获取到当前播放的位置(开源库中有相关方法)判断是否在屏幕可见,不可见就回收;具体看代码

@Override            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {                super.onScrolled(recyclerView, dx, dy);                //大于0说明有播放                if (GSYVideoManager.instance().getPlayPosition() >= 0) {                    //当前播放的位置                    int position = GSYVideoManager.instance().getPlayPosition();                    //对应的播放列表TAG                    if (GSYVideoManager.instance().getPlayTag().equals(HomeAdapter.TAG) && (position < firstVisibleItem || position > lastVisibleItem)) {                        GSYVideoManager.releaseAllVideos();                    }                }            }

第三点:屏幕处于静止时才开始播放,只要播放的逻辑写在onScrollStateChangedSCROLL_STATE_IDLE 状态下即可;

@Override            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {                super.onScrollStateChanged(recyclerView, newState);                switch (newState) {                    case SCROLL_STATE_IDLE: //滚动停止                        autoPlayVideo(recyclerView);                        break;                }            }void autoPlayVideo(RecyclerView view) {        for (int i = 0; i < visibleCount; i++) {            if (view != null && view.getChildAt(i) != null && view.getChildAt(i).findViewById(R.id.video_item_player) != null) {                HomeGSYVideoPlayer homeGSYVideoPlayer = (HomeGSYVideoPlayer) view.getChildAt(i).findViewById(R.id.video_item_player);                Rect rect = new Rect();                homeGSYVideoPlayer.getLocalVisibleRect(rect);                int videoheight = homeGSYVideoPlayer.getHeight();                if (rect.top == 0 && rect.bottom == videoheight) {                    if (homeGSYVideoPlayer.getCurrentState() == homeGSYVideoPlayer.CURRENT_STATE_NORMAL || homeGSYVideoPlayer.getCurrentState() == homeGSYVideoPlayer.CURRENT_STATE_ERROR) {                        homeGSYVideoPlayer.getStartButton().performClick();                    }                    return;                }            }        }        GSYVideoPlayer.releaseAllVideos();    }

autoPlayVideo方法里面就是通过 循环遍历 可见区域的播放器 然后通过 getLocalVisibleRect(rect) 方法计算出谁完全显示出来,对应方法可以查看getLocalVisibleRect 写的很详细。最后判断如果播放器处于可播放的状态即调用start按钮播放。

因为是公司代码,所以很多地方不能开放出来,忘见谅。最后附上主要完整代码:

 public int firstVisibleItem, lastVisibleItem, visibleCount;    public void loadListener() {        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {            boolean scrollState = false;            @Override            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {                super.onScrollStateChanged(recyclerView, newState);                switch (newState) {                    case SCROLL_STATE_IDLE: //滚动停止                        scrollState = false;//                        autoPlayVideo(recyclerView);                        break;                    case SCROLL_STATE_DRAGGING: //手指拖动                        scrollState = true;                        break;                    case SCROLL_STATE_SETTLING: //惯性滚动                        scrollState = true;                        break;                }            }            @Override            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {                super.onScrolled(recyclerView, dx, dy);                firstVisibleItem = layoutManager.findFirstVisibleItemPosition();                lastVisibleItem = layoutManager.findLastVisibleItemPosition();                visibleCount = lastVisibleItem - firstVisibleItem;                //大于0说明有播放                if (GSYVideoManager.instance().getPlayPosition() >= 0) {                    //当前播放的位置                    int position = GSYVideoManager.instance().getPlayPosition();                    //对应的播放列表TAG                    if (GSYVideoManager.instance().getPlayTag().equals(HomeAdapter.TAG) && (position < firstVisibleItem || position > lastVisibleItem)) {                        GSYVideoManager.onPause();                    }                }            }        });    }    private void autoPlayVideo(RecyclerView view) {        for (int i = 0; i < visibleCount; i++) {            if (view != null && view.getChildAt(i) != null && view.getChildAt(i).findViewById(R.id.video_item_player) != null) {                HomeGSYVideoPlayer homeGSYVideoPlayer = (HomeGSYVideoPlayer) view.getChildAt(i).findViewById(R.id.video_item_player);                Rect rect = new Rect();                homeGSYVideoPlayer.getLocalVisibleRect(rect);                int videoheight = homeGSYVideoPlayer.getHeight();                if (rect.top == 0 && rect.bottom == videoheight) {                    if (homeGSYVideoPlayer.getCurrentState() == homeGSYVideoPlayer.CURRENT_STATE_NORMAL || homeGSYVideoPlayer.getCurrentState() == homeGSYVideoPlayer.CURRENT_STATE_ERROR) {                        homeGSYVideoPlayer.getStartButton().performClick();                    }                    return;                }            }        }        GSYVideoPlayer.releaseAllVideos();    }

说到这里还有一点可以说下,就是给视频弄圆角的时候,具体效果可以看上图,这里需要给TextureView设置圆角,一般的通过写shape设置background已经不适用了,好在网上找到一个方法:

public class TextureVideoViewOutlineProvider extends ViewOutlineProvider {    private float mRadius;    public TextureVideoViewOutlineProvider(float radius) {        this.mRadius = radius;    }    @Override    public void getOutline(View view, Outline outline) {        Rect rect = new Rect();        view.getGlobalVisibleRect(rect);        int leftMargin = 0;        int topMargin = 0;        Rect selfRect = new Rect(leftMargin, topMargin,                rect.right - rect.left - leftMargin, rect.bottom - rect.top - topMargin);        outline.setRoundRect(selfRect, mRadius);    }}

最后给view设置就行:

mVideoView.setOutlineProvider(new TextureVideoViewOutlineProvider(radius));mVideoView.setClipToOutline(true);

好了,今天的分享就到这里了,也是百忙中抽空写完了,喜欢可以点播关注,不喜欢的可以提点意见 ~_~ 。

原创粉丝点击