视频
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);
}
});
}