Skip to content
This repository has been archived by the owner on Aug 9, 2022. It is now read-only.

实现了RecycleView自动播放视频的效果,分享给大家 #1670

Closed
SiXuManYan opened this issue Mar 8, 2018 · 22 comments · May be fixed by #1686
Closed

实现了RecycleView自动播放视频的效果,分享给大家 #1670

SiXuManYan opened this issue Mar 8, 2018 · 22 comments · May be fixed by #1686

Comments

@SiXuManYan
Copy link

SiXuManYan commented Mar 8, 2018

谢谢作者@lipangit 开源出来如此优秀的框架,受益匪浅
项目中实现了类似汽车之家那种滑动RecycleView 自动播放视频的效果,分享给大家

原理

1.添加OnScrollListener 监听 ,循环遍历 可见区域(就是 lastVisibleItem - firstVisibleItem的个数)
内的播放器控件
最后通过 getLocalVisibleRect(rect) 方法计算出哪个播放器完全显示出来,然后startVideo()进行播放

2.在适当的时机跳出循环,只处理可见区域内的第一个播放器

getLocalVisibleRect原理可以参照这个链接

我使用的相关版本

... 
compileSdkVersion 23
buildToolsVersion '25.0.3'
minSdkVersion 16
targetSdkVersion 23
...
compile 'cn.jzvd:jiaozivideoplayer:6.2.7'

自己项目中RecycleView实现视频自动播放的代码如下

AutoPlayScrollListener listener = new AutoPlayScrollListener ();
recyclerView.addOnScrollListener(listener);
    /**
     * 监听recycleView滑动状态,
     * 自动播放可见区域内的第一个视频
     */
    private static class AutoPlayScrollListener extends RecyclerView.OnScrollListener {

        private int firstVisibleItem = 0;
        private int lastVisibleItem = 0;
        private int visibleCount = 0;

        /**
         * 被处理的视频状态标签
         */
        private enum VideoTagEnum {

            /**
             * 自动播放视频
             */
            TAG_AUTO_PLAY_VIDEO,

            /**
             * 暂停视频
             */
            TAG_PAUSE_VIDEO
        }

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);

            switch (newState) {
                case RecyclerView.SCROLL_STATE_IDLE:
                    autoPlayVideo(recyclerView, VideoTagEnum.TAG_AUTO_PLAY_VIDEO);
                default:
                    // 滑动时暂停视频 autoPlayVideo(recyclerView, VideoTagEnum.TAG_PAUSE_VIDEO);
                    break;
            }

        }

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

            RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
            if (layoutManager instanceof LinearLayoutManager) {
                LinearLayoutManager linearManager = (LinearLayoutManager) layoutManager;
                firstVisibleItem = linearManager.findFirstVisibleItemPosition();
                lastVisibleItem = linearManager.findLastVisibleItemPosition();
                visibleCount = lastVisibleItem - firstVisibleItem;
            }

        }

        /**
         * 循环遍历 可见区域的播放器
         * 然后通过 getLocalVisibleRect(rect)方法计算出哪个播放器完全显示出来
         * <p>
         * getLocalVisibleRect相关链接:http://www.cnblogs.com/ai-developers/p/4413585.html
         *
         * @param recyclerView
         * @param handleVideoTag 视频需要进行状态
         */
        private void autoPlayVideo(RecyclerView recyclerView, VideoTagEnum handleVideoTag) {
            for (int i = 0; i < visibleCount; i++) {
                if (recyclerView != null && recyclerView.getChildAt(i) != null && recyclerView.getChildAt(i).findViewById(R.id.videoplayer) != null) {
                    JZVideoPlayerStandard homeGSYVideoPlayer = (JZVideoPlayerStandard) recyclerView.getChildAt(i).findViewById(R.id.videoplayer);

                    Rect rect = new Rect();
                    homeGSYVideoPlayer.getLocalVisibleRect(rect);
                    int videoheight = homeGSYVideoPlayer.getHeight();
                    if (rect.top == 0 && rect.bottom == videoheight) {
                        handleVideo(handleVideoTag, homeGSYVideoPlayer);
                        // 跳出循环,只处理可见区域内的第一个播放器
                        break;
                    }
                }
            }

        }

        /**
         * 视频状态处理
         *
         * @param handleVideoTag     视频需要进行状态
         * @param homeGSYVideoPlayer JZVideoPlayer播放器
         */
        private void handleVideo(VideoTagEnum handleVideoTag, JZVideoPlayerStandard homeGSYVideoPlayer) {
            switch (handleVideoTag) {
                case TAG_AUTO_PLAY_VIDEO:
                    if ((homeGSYVideoPlayer.currentState != JZVideoPlayerStandard.CURRENT_STATE_PLAYING)) {
                        // 进行播放
                        homeGSYVideoPlayer.startVideo();
                    }
                    break;
                case TAG_PAUSE_VIDEO:
                    if ((homeGSYVideoPlayer.currentState != JZVideoPlayerStandard.CURRENT_STATE_PAUSE)) {
                        // 模拟点击,暂停视频
                        homeGSYVideoPlayer.startButton.performClick();
                    }
                    break;
                default:
                    break;
            }
        }


    }

对于item滑出可见区域后,进行视频回收的逻辑,可以参照demo中的ActivityListViewRecyclerView
相关代码如下所示

// recycle this video when the item leaves the screen.
        recyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
            @Override
            public void onChildViewAttachedToWindow(View view) {

            }

            @Override
            public void onChildViewDetachedFromWindow(View view) {
                JZVideoPlayer jzvd = view.findViewById(R.id.videoplayer);
                if (jzvd != null && JZUtils.dataSourceObjectsContainsUri(jzvd.dataSourceObjects, JZMediaManager.getCurrentDataSource())) {
                    if(JZVideoPlayerManager.getCurrentJzvd().currentScreen != JZVideoPlayer.SCREEN_WINDOW_FULLSCREEN){
                        JZVideoPlayer.releaseAllVideos();
                    }
                }
            }
        });
    }
@lipangit
Copy link
Owner

lipangit commented Mar 8, 2018

漂亮,兄弟,能不能提交一个pr,把在不改库的情况下把这个功能加到demo里

@SiXuManYan
Copy link
Author

好的,只是一直都没用过gayhub Pull Request,我研究下秘籍,马上怼上去

@suchengjian
Copy link

demo视频蜜汁好评

@MelodyLucien
Copy link

thumbs up for demo. A great library

@koushik16github
Copy link

@SiXuManYan can you share your full source code?

@lipangit
Copy link
Owner

@koushik16github see this pr but not complete yet #1671

SiXuManYan added a commit to SiXuManYan/JiaoZiVideoPlayer that referenced this issue Mar 14, 2018
@koushik16github
Copy link

setPrefs_.wifiAutoPlayVideo() what is this method? please share

@SiXuManYan
Copy link
Author

@koushik16github
It's just a Boolean type of switch variable that you can replace with your own.
It is important to note, Sir, that I have submitted new code on the new PR, please refer to the new url link.
I will update this code on this page later.

@lipangit
Copy link
Owner

@SiXuManYan 加油小宝贝

@SiXuManYan
Copy link
Author

@lipangit 参照了#1549的方案,
已经实现了静音播放的相关逻辑(列表视频自动播放时静音,全屏时取消静音),在此基础上稍许优化了一些

代码我需要传上去吗

@lipangit
Copy link
Owner

提交pr @SiXuManYan

@magical-xu
Copy link

我觉得 自动播放那段代码
homeGSYVideoPlayer.currentState != JZVideoPlayerStandard.CURRENT_STATE_PLAYING
这个判断不对吧,比如播放完毕的显示重播那个状态,轻轻划一下又开始播放了
应该是 homeGSYVideoPlayer.currentState== JZVideoPlayerStandard.CURRENT_STATE_NORMAL
只有这个状态才自动播

而且那个判断滑出屏幕可见区域自动停止的代码,判断的不太严谨,如果视频地址是无效,类似error这种状态 player.dataSourceObjects 都是 null的

还有个问题是自动播的时候,如果视频地址是无效的,dataSourceOjbects是 null , 走到 JZUtils.getCurrentFromDataSource(); 这个方法就崩了,希望作者将这种参数传递的校验做的更严谨些
_15215315919286

以上都是个人的意见,谢谢各位大大提供这么好的思路和好用的库

@SiXuManYan
Copy link
Author

@magical-xu
谢谢老哥的指正,
自动播放那部分我想的是,实现成类似《汽车之家》那样,
只要滑动到需要播放的那个视频Item就直接播放。
所以判断逻辑粗暴的写成下面这样:

 if ((homeGSYVideoPlayer.currentState == JZVideoPlayerStandard.CURRENT_STATE_PLAYING)) {
     // 进行播放
     homeGSYVideoPlayer.startVideo();
 }

像下面逻辑判断的话,显示的现象是:停止滑动后不会自动播放那些 ”已经播放完一遍的视频了“

homeGSYVideoPlayer.currentState== JZVideoPlayerStandard.CURRENT_STATE_NORMAL

可以结合自己项目的具体需求来选择判断条件


回收的那部分可能要改JZVideo源码逻辑,就需要作者来看了

@i91h1r
Copy link

i91h1r commented Mar 21, 2018

请问 当我这样判断时候报这个错
2
1

当换成这样判断时候,滑动能正常播放
3
但是这样的判断有一个问题是:
将recycleview 向上滑动很长一段距离之后 再回来,视频就不会自动播放了,将recycleview向下滑动 没有问题,依旧能正常播放。

请问这个是什么问题?

@lipangit
Copy link
Owner

@hyr0318 断点滑到屏幕中的时候,setUp里面的url是不是有值,这个应该是url为null造成的

@i91h1r
Copy link

i91h1r commented Mar 21, 2018

@lipangit 恩,好像是的,但是我的视频的item 是在第二页,我在第一页数据时候怎么也走了这里面来了额

@lipangit
Copy link
Owner

断点或者打log,数据部分是setUp函数管的,看看这函数的运行是不是有问题

@xiaoting000
Copy link

如果在滑动时视频处在预加载阶段, 滑动就会一直start,没滑动一次就重新加载播放,所以处理滑动视频播放可以加一个条件保证如果滑动阶段是在加载的就等加载完成再调用startVideo,
if ((homeGSYVideoPlayer.currentState != JZVideoPlayerStandard.CURRENT_STATE_PLAYING && homeGSYVideoPlayer.currentState != JZVideoPlayerStandard.CURRENT_STATE_PREPARING)) {
// 进行播放
homeGSYVideoPlayer.startVideo();
}
break;

@SiXuManYan 谢谢哈,我用的你这个实现的自动播放,感谢

@SiXuManYan
Copy link
Author

@xiaoting000 谢谢指正,我也是受益于作者的这个项目。
之前提交了个pr,代码可能会比这个更新一些,也可以看一下这个。#1686
同为开发者,我们一起加油~

@lipangit
Copy link
Owner

lipangit commented May 8, 2018

想起来了,@SiXuManYan 你的提交我测试过,有问题,不能完美运行

@shuaimango
Copy link

@lipangit
Copy link
Owner

@shuaimango 兄弟,能把这个加到demo中吗,给大家参考

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants