1-Android开发知识android UI系列专题

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

2020-01-02  本文已影响0人  龍and胡歌

前言:之前项目里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;
    }
}
上一篇下一篇

猜你喜欢

热点阅读