项目模板

视频

2020-09-13  本文已影响0人  夜沐下的星雨

在我们平常使用视频是使用饺子视频,或者自定义视频
今天我使用了一个GSYVideoPlaver (实现了多功能的视频播放器)的依赖。通过它自定义自己所需要的功能(视频,广告视频自动播放器)
如下图:创建的模块:
每次使用只需要在app 中 implementation project(path:':libvideo')即可


video.png

使用依赖:

  implementation 'com.shuyu:GSYVideoPlayer:7.1.5'

使用了WDSVideo 继承StandardGSYVideoPlayer创建自定义视频播放器


public class WDSVideo extends StandardGSYVideoPlayer {

   //图片控件
    private ImageView mCoverImage;

    public WDSVideo(Context context, Boolean fullFlag) {
        super(context, fullFlag);
    }

    public WDSVideo(Context context) {
        super(context);
    }

    public WDSVideo(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void init(Context context) {
       // super.init(context);


        // GSYVideoView int
        if(getActivityContext() != null) {
            this.mContext = getActivityContext();
        } else {
            this.mContext = context;
        }

        initInflate(mContext);

        mTextureViewContainer = (ViewGroup) findViewById(R.id.surface_container);
        if (isInEditMode())
            return;
        mScreenWidth = mContext.getResources().getDisplayMetrics().widthPixels;
        mScreenHeight = mContext.getResources().getDisplayMetrics().heightPixels;
        mAudioManager = (AudioManager) mContext.getApplicationContext().getSystemService(Context.AUDIO_SERVICE);



        // GSYVideoControlView
        mStartButton = findViewById(R.id.start);
        mTitleTextView = (TextView) findViewById(R.id.title);
        mBackButton = (ImageView) findViewById(R.id.back);
        mFullscreenButton = (ImageView) findViewById(R.id.fullscreen);
        mProgressBar = (SeekBar) findViewById(R.id.progress);
        mCurrentTimeTextView = (TextView) findViewById(R.id.current);
        mTotalTimeTextView = (TextView) findViewById(R.id.total);
        mBottomContainer = (ViewGroup) findViewById(R.id.layout_bottom);
        mTopContainer = (ViewGroup) findViewById(R.id.layout_top);
        mBottomProgressBar = (ProgressBar) findViewById(R.id.bottom_progressbar);
        mThumbImageViewLayout = (RelativeLayout) findViewById(R.id.thumb);
        mLockScreen = (ImageView) findViewById(R.id.lock_screen);

        mLoadingProgressBar = findViewById(R.id.loading);


        if (isInEditMode())
            return;

        if (mStartButton != null) {
            mStartButton.setOnClickListener(this);
        }

        if (mFullscreenButton != null) {
            mFullscreenButton.setOnClickListener(this);
            mFullscreenButton.setOnTouchListener(this);
        }

        if (mProgressBar != null) {
            mProgressBar.setOnSeekBarChangeListener(this);
        }

        if (mBottomContainer != null) {
            mBottomContainer.setOnClickListener(this);
        }

        if (mTextureViewContainer != null) {
            mTextureViewContainer.setOnClickListener(this);
            mTextureViewContainer.setOnTouchListener(this);
        }

        if (mProgressBar != null) {
            mProgressBar.setOnTouchListener(this);
        }

        if (mThumbImageViewLayout != null) {
            mThumbImageViewLayout.setVisibility(GONE);
            mThumbImageViewLayout.setOnClickListener(this);
        }
        if (mThumbImageView != null && !mIfCurrentIsFullscreen && mThumbImageViewLayout != null) {
            mThumbImageViewLayout.removeAllViews();
            resolveThumbImage(mThumbImageView);
        }

        if (mBackButton != null)
            mBackButton.setOnClickListener(this);

        if (mLockScreen != null) {
            mLockScreen.setVisibility(GONE);
            mLockScreen.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mCurrentState == CURRENT_STATE_AUTO_COMPLETE ||
                            mCurrentState == CURRENT_STATE_ERROR) {
                        return;
                    }
                    lockTouchLogic();
                    if (mLockClickListener != null) {
                        mLockClickListener.onClick(v, mLockCurScreen);
                    }
                }
            });
        }
        if (getActivityContext() != null) {
            mSeekEndOffset = CommonUtil.dip2px(getActivityContext(), 50);
        }
        // GSYBaseVideoPlayer
        mSmallClose = findViewById(R.id.small_close);

        //StandardGSYVideoPlayer

        if (mBottomProgressDrawable != null) {
            mBottomProgressBar.setProgressDrawable(mBottomProgressDrawable);
        }

        if (mBottomShowProgressDrawable != null) {
            mProgressBar.setProgressDrawable(mBottomProgressDrawable);
        }

        if (mBottomShowProgressThumbDrawable != null) {
            mProgressBar.setThumb(mBottomShowProgressThumbDrawable);
        }
        mCoverImage = new ImageView(getContext());
        mCoverImage.setScaleType(ImageView.ScaleType.CENTER_CROP);
        setThumbImageView(mCoverImage);
    }


    public ImageView getCoverView(){
        return mCoverImage;
    }

    @Override
    protected void startPrepare() {
        super.startPrepare();
    }

    @Override
    public int getLayoutId() {
        return R.layout.lib_video_layout;
    }
    // 自定义 开始/ 暂停/ 错误的图标
    @Override
    protected void updateStartImage() {
        if (mStartButton instanceof ENPlayView) {
            ENPlayView enPlayView = (ENPlayView) mStartButton;
            enPlayView.setDuration(500);
            if (mCurrentState == CURRENT_STATE_PLAYING) {
                enPlayView.play();
            } else if (mCurrentState == CURRENT_STATE_ERROR) {
                enPlayView.pause();
            } else {
                enPlayView.pause();
            }
        } else if (mStartButton instanceof ImageView) {
            ImageView imageView = (ImageView) mStartButton;
            if (mCurrentState == CURRENT_STATE_PLAYING) {
                imageView.setImageResource(R.drawable.video_click_pause_selector);
            } else if (mCurrentState == CURRENT_STATE_ERROR) {
                imageView.setImageResource(R.drawable.video_click_error_selector);
            } else {
                imageView.setImageResource(R.drawable.video_click_play_selector);
            }
        }
    }
    public boolean isInInPause(){
        return (mCurrentState >= 0 && mCurrentState == CURRENT_STATE_PAUSE);
    }

}

创建滚动视频监听器:

//视频播放
public class MkVideoScrollListener extends RecyclerView.OnScrollListener {
    int firstVisibleItem;
    int lastVisibleItem;
    LinearLayoutManager linearLayoutManager;
    private String tag;
    public MkVideoScrollListener(LinearLayoutManager linearLayoutManager){
        this.linearLayoutManager=linearLayoutManager;
    }

    @Override
    public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        firstVisibleItem =linearLayoutManager.findFirstVisibleItemPosition();
        lastVisibleItem=linearLayoutManager.findLastVisibleItemPosition();

        //如果大于0说明播放了
        if (GSYVideoManager.instance().getPlayPosition()>=0&&GSYVideoManager.instance().getPlayTag().equals(tag)){
            //当前播放的位置
            int position = GSYVideoManager.instance().getPlayPosition();
            //对应的播放列表TAG
            if ((position<firstVisibleItem||position>lastVisibleItem)){
                //如果滑出去了上面和下面就是否,和今日头条一样
                //是否全屏
                if (!GSYVideoManager.isFullState((Activity) recyclerView.getContext())){
                    GSYVideoManager.releaseAllVideos();
                    recyclerView.getAdapter().notifyItemChanged(position);
                }
            }
        }
    }

    @Override
    public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        if (newState==RecyclerView.SCROLL_STATE_IDLE){
            play(recyclerView);
        }
    }
    /**
     *
     * 从第一可见的position  到最后一个可见的position 挨个遍历
     *
     * 通过 position 找到 对应的item view
     *
     * 在通过 item view 找到 holder 对象
     *
     *
     * 如果这个holder 是一个视频广告的holder
     *          如果这个item 视频播放器全部可见 那么通过这个item view 找到 对应的播放器控件,然后调用start 播放
     *
     */
    private void play(RecyclerView recyclerView) {

        // 遍历第一个可见 item 和 最后一个可见item 之间的 是否有 视频广告item
        for (int i = firstVisibleItem; i <= lastVisibleItem; i++) {

            View itemView = linearLayoutManager.findViewByPosition(i);// 根据 position  找到 item view;
            if (itemView==null){
                return;
            }
            RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(itemView); // 更具 item  view 找到对应 holder

            if(holder instanceof MkAutoPlayVideoHolder){ // 如果这个holder 实现了这个接口,意味着这个holder 对应的item 里面的视频会自动播放

                WDSVideo video =  ((MkAutoPlayVideoHolder) holder).getVideoVIew();


                int itemViewTop = itemView.getTop(); // item 在 recycler view 中的 top

                int videoHeight = video.getHeight();// 视频控件的高度

                int videoTopYInRecyclerView = itemViewTop + video.getTop(); // video view 在 recycler view (祖宗容器) 的 top 值


                if (videoTopYInRecyclerView < 0) { // 如果video view 顶部有一部分不在recycler view 里面
                    // 顶部不在 recycler  view 里面的部分小于制定的值,那么播放
                    if (Math.abs(videoTopYInRecyclerView) <= getPlayOrStopThreshold(videoHeight)) {
                        if(video.isInInPause()){
                            video.onVideoResume(false);
                        }else if(!video.isInPlayingState()){
                            video.startPrepare();
                        }
                        break;
                    }else{
                        if(video.isInPlayingState()){
                            video.onVideoPause();
                        }
                    }
                }else{
                    int videoBottomYInRecyclerView = itemView.getTop() + video.getBottom(); // video view 在 recycler vie 中的 bot
                    int excess = videoBottomYInRecyclerView - recyclerView.getHeight(); // video view 在 recycler view 中超出部分
                    //  如果video view 整个都在recycler view  里面或者 video 有一部分已经超出了 recycler view 下面一部分,但是超出部分不足 video view 高度的三分之一
                    if (excess < getPlayOrStopThreshold(videoHeight)) {
                        if(video.isInInPause()){
                            video.onVideoResume(false);
                        }else if(!video.isInPlayingState()){
                            video.startPrepare();
                        }
                        break;
                    }else{
                        if(video.isInPlayingState()){
                            video.onVideoPause();
                        }
                    }
                }
            }


        }
    }
    /**
     * 返回 video view 上边 或者 下边 垂直方向上在屏幕之外的距离,如果大于这个距离 就停止播放,小于这个距离就自动播放
     * 默认是高度的 1/3,   返回 0 表示,只有整个Video View 都在屏幕上可见是才播放。
     * @param videoHeight
     * @return
     */
    public int getPlayOrStopThreshold(int videoHeight){
        return 0;
    }


    // 看一下是否有满足自动播放的 video
    public static void playIfNeed(final RecyclerView recyclerView){
        recyclerView.post(new Runnable() {
            @Override
            public void run() {
                recyclerView.smoothScrollBy(0,1);
            }
        });
    }
}

创建MkAutoPlayVideoHolder (如果这个holder 实现了这个接口,意味着这个holder 对应的item 里面的视频会自动播放)

public interface MkAutoPlayVideoHolder {
    WDSVideo getVideoVIew();
}

创建一个清空视频管理器:


public class MkEmptyVideo extends WDSVideo {

    public MkEmptyVideo(Context context, Boolean fullFlag) {
        super(context, fullFlag);
    }
    public MkEmptyVideo(Context context) {
        super(context);
    }
    public MkEmptyVideo(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public int getLayoutId() {
        return R.layout.lib_video_empty_layout;
    }

   //触摸上的逻辑
    @Override
    protected void touchSurfaceMoveFullLogic(float absDeltaX, float absDeltaY) {
        super.touchSurfaceMoveFullLogic(absDeltaX, absDeltaY);
        //不给触摸快进,如果需要,屏蔽下方代码即可
        mChangePosition = false;

        //不给触摸音量,如果需要,屏蔽下方代码即可
        mChangeVolume = false;

        //不给触摸亮度,如果需要,屏蔽下方代码即可
        mBrightness = false;
    }

    @Override
    protected void touchDoubleUp() {
        super.touchDoubleUp();
        //不需要双击暂停
    }
}

那么我们如何使用这个vidoe 呢?
首先是布局:

 <com.wds.libvideo.WDSVideo
        android:id="@+id/playerVideo"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:scaleType="centerCrop"
        app:layout_constraintDimensionRatio="w,1:1.77"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

在viewHolder 视频器中使用:

    private   class VideoHolder extends NewsHolder{

        private ItemNewsVideoBinding binding;
        private GSYVideoOptionBuilder gsyVideoOptionBuilder;
        public VideoHolder(@NonNull View itemView) {
            super(itemView);
            binding = ItemNewsVideoBinding.bind(itemView);
            gsyVideoOptionBuilder=new GSYVideoOptionBuilder();
        }

        @Override
        public void bindData(News news) {
            binding.title.setText(news.getTheme());
            // GlideApp.with(itemView).load(news.getImageUrl()).into(binding.cover);
            binding.label.setText(news.getColumn_name());
            gsyVideoOptionBuilder
                    .setIsTouchWiget(false)
                    //.setThumbImageView(imageView)
                    .setUrl(news.getVideo_url())
                    .setCacheWithPlay(false)
                    .setRotateViewAuto(true)
                    .setLockLand(true)
                    .setPlayTag(mPlayTag)
                    .setShowFullAnimation(true)
                    .setNeedShowWifiTip(false)
                    .setNeedLockFull(true)
                    .setVideoAllCallBack(new GSYSampleCallBack() {
                        @Override
                        public void onPrepared(String url, Object... objects) {
                            super.onPrepared(url, objects);
                            if (!binding.playerVideo.isIfCurrentIsFullscreen()) {
                                //静音
                                GSYVideoManager.instance().setNeedMute(true);
                            }

                        }

                        @Override
                        public void onQuitFullscreen(String url, Object... objects) {
                            super.onQuitFullscreen(url, objects);
                            //全屏不静音
                            GSYVideoManager.instance().setNeedMute(true);
                        }

                        @Override
                        public void onEnterFullscreen(String url, Object... objects) {
                            super.onEnterFullscreen(url, objects);
                            GSYVideoManager.instance().setNeedMute(false);
                            binding.playerVideo.getCurrentPlayer().getTitleTextView().setText((String)objects[0]);
                        }
                    }).build(binding.playerVideo);
            //增加title
            //binding.playerVideo.getTitleTextView().setVisibility(View.VISIBLE);

            //设置返回键
            binding.playerVideo.getBackButton().setVisibility(View.VISIBLE);
            GlideApp.with(itemView).load(news.getImageUrl()).into( binding.playerVideo.getCoverView());
            //设置全屏按键功能
            binding.playerVideo.getFullscreenButton().setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    resolveFullBtn(binding.playerVideo);
                }
            });

        }
上一篇下一篇

猜你喜欢

热点阅读