美文网首页1-Android开发知识android UI系列专题
Android的RecyclerView视频自动播放(滑动停止时

Android的RecyclerView视频自动播放(滑动停止时

作者: 龍and胡歌 | 来源:发表于2020-01-02 22:20 被阅读0次

    前言:之前项目里feed里需要自动播放视频,老代码用的是第三方,但是遇到的视频不能正确自动播放的情况,于是自己动手写了一个。

    思路:在recyclerview的OnScrollListener中进行滑动监听,当滑动停止时,去判断视频的view可见度为多少,进而判断是否需要进行自动播放。

    import android.view.View;
    //辅助接口
    public interface AutoPlayItem {
        void setActive();
        void deactivate();
        View getAutoplayView();
    }
    

    主要的工具类,有两种播放模式,MODE_PLAY_FIRST播放第一个可见的视频,MODE_PLAY_CENTER播放靠中间的可见的一个视频.
    需要用到globalVisibleRect或者getLocalVisibleRect,通过源码可以看到getLocalVisibleRect调用了globalVisibleRect。可参考:https://www.jianshu.com/p/2aa908f6a2e6
    需要知道的是globalVisibleRect获取到的可见区域的坐标是屏幕中真实的坐标,getLocalVisibleRect获取到的是0开始的坐标。

    //源码
        public final boolean getGlobalVisibleRect(Rect r) {
            return getGlobalVisibleRect(r, null);
        }
    
        public final boolean getLocalVisibleRect(Rect r) {
            final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point();
            if (getGlobalVisibleRect(r, offset)) {
                r.offset(-offset.x, -offset.y); // make r local
                return true;
            }
            return false;
        }
    

    由于需要计算view的可见百分比,所以还用到的了getMeasuredHeight(),通过源码可知这个方法获取到的是view向父布局申请的高度,实际的高度可能会因为屏幕限制而没有那么高。
    另外,getHight()方法获取到的是父布局通过layout方法实际给view的高度。
    可参考:https://www.jianshu.com/p/27e765cf24c2

    //源码
    
    public final int getMeasuredHeight() {
            return mMeasuredHeight & MEASURED_SIZE_MASK;
        }
    
     private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
            mMeasuredWidth = measuredWidth;
            mMeasuredHeight = measuredHeight;
    
            mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
        }
    
    

    因为需要播放屏幕中间的那个视频,所以还要知道屏幕的高度,我用的是
    getResources().getDisplayMetrics().heightPixels;

    /**
     * 自动播放的工具
     */
    public class AutoPlayTool {
        private AutoPlayItem mHolder;
        private int visiblePercent=60;
        public static int MODE_PLAY_FIRST=0;
        public static int MODE_PLAY_CENTER=1;
        private int mode=MODE_PLAY_FIRST;
        public AutoPlayTool() {
    
        }
        public AutoPlayTool(int visiblePercent) {
            this.visiblePercent = visiblePercent;
        }
    
        public AutoPlayTool(int visiblePercent, int mode) {
            this.visiblePercent = visiblePercent;
            this.mode = mode;
        }
    
        public void setMode(int mode) {
            this.mode = mode;
        }
    
        /**
         * 当滑动停止的时候,开始视频播放
         * @param recyclerView
         * @return
         */
        public int onActiveWhenNoScrolling(RecyclerView recyclerView){
            LinearLayoutManager layoutManager=null;
            if(recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
                layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
            }
            if(layoutManager!=null) {
                int firstItemPosition = layoutManager.findFirstVisibleItemPosition();
                int lastItemPosition=layoutManager.findLastVisibleItemPosition();
                LinkedHashMap<Integer ,AutoPlayItem> items=new LinkedHashMap();
                while (firstItemPosition<=lastItemPosition){
                    RecyclerView.ViewHolder holder=recyclerView.findViewHolderForLayoutPosition(firstItemPosition);
    
                    if(holder instanceof AutoPlayItem){
                        View view=(((AutoPlayItem) holder)).getAutoplayView();
                        if(view!=null&&getVisible(view,visiblePercent)){
                            if(mode==MODE_PLAY_FIRST){//优先播放第一个的情况
                                ((AutoPlayItem) holder).setActive();
                                mHolder= ((AutoPlayItem) holder);
                                return firstItemPosition;
                            }
                            items.put(firstItemPosition,((AutoPlayItem) holder));
                        }
                    }
                    firstItemPosition++;
                }
                //下面的逻辑是播放靠中间的视频
                int d=Integer.MAX_VALUE;
                AutoPlayItem findHolder=null;
                int position=-1;
                //找出距离中间最近的一个
                for(Map.Entry<Integer,AutoPlayItem> entry : items.entrySet()) {
                    int d2=getDistanceFromCenter(entry.getValue().getAutoplayView());
                    if(d2<d){
                        findHolder = entry.getValue();
                        d=d2;
                        position=entry.getKey();
                    }
                }
                if(mHolder!=findHolder) {
                    if (mHolder != null) {
                        mHolder.deactivate();
                    }
                    mHolder=findHolder;
                }
                if (mHolder != null) {
                    mHolder.setActive();
                    return position;
                }
            }
            return -1;
        }
    //当视频画出屏幕时停止播放
        public void onScrolledAndDeactivate(RecyclerView recyclerView){
            if(mHolder!=null&&mHolder.getAutoplayView()!=null&&!getVisible(mHolder.getAutoplayView(),visiblePercent)){
                mHolder.deactivate();
            }
        }
    
        /**
         * 用于停止滑出去的视频
         */
        public void onScrolledAndDeactivate(){
            if(mHolder!=null&&mHolder.getAutoplayView()!=null&&!getVisible(mHolder.getAutoplayView(),visiblePercent)){
                mHolder.deactivate();
            }
        }
    
        public void setVisiblePercent(int visiblePercent) {
            this.visiblePercent = visiblePercent;
        }
    
        private int getVisiblePercent(View v) {
            Rect r =new Rect();
            boolean visible = v.getLocalVisibleRect(r);
            if (visible&& v.getMeasuredHeight()>0) {
                int percent = 100 * r.height() / v.getMeasuredHeight();
                return percent;
            }
            return -1;
        }
    
        private boolean getVisible(View v, int value) {
            Rect r = new Rect();
            boolean visible = v.getLocalVisibleRect(r);
            if (visible&&v.getVisibility()==View.VISIBLE) {
                if (getVisiblePercent(v) >= value) {
                    return true;
                } else {
                    return false;
                }
            }
            return false;
        }
        private int getDistanceFromCenter(View view){
            int centerHeight=(int) (DensityUtil.getScreenHeight()/2.3);//中间线靠上一点,
            //项目代码原因,可以写getResources().getDisplayMetrics().heightPixels;
            int[] viewLocation = new int[2];
            view.getLocationOnScreen(viewLocation);
            return Math.abs(viewLocation[1]+view.getHeight()/2-centerHeight);
        }
    
    }
    

    在recyclerview中使用

        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                AutoPlayTool autoPlayTool=new AutoPlayTool(60,1);
                @Override
                public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    if(newState==RecyclerView.SCROLL_STATE_IDLE){
                        autoPlayTool.onActiveWhenNoScrolling(recyclerView);
                    }
                }
    
                @Override
                public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    autoPlayTool.onScrolledAndDeactivate();
                }
            });
    

    最后,ViewHold需要继承AutoPlayItem接口。
    在setActive() 方法中开始自动播放,在deactivate()停止播放,getAutoplayView()返回你的videoview。

    public class ViewHoldVideo  extends RecyclerView.ViewHolder implements AutoPlayItem{
    
        public ViewHoldVideo(@NonNull View itemView) {
            super(itemView);
        }
    
        @Override
        public void setActive() {
    
        }
    
        @Override
        public void deactivate() {
    
        }
    
        @Override
        public View getAutoplayView() {
            return null;
        }
    }
    

    相关文章

      网友评论

        本文标题:Android的RecyclerView视频自动播放(滑动停止时

        本文链接:https://www.haomeiwen.com/subject/qlraoctx.html