这里有一个是TextureView的动态添加,动态添加的好处是你可以在不停止视频的状况下载不同的逻辑播放器中切换视频播放,比如列表全屏。
protected void addTextureView() {
if (mTextureViewContainer.getChildCount() > 0) {
mTextureViewContainer.removeAllViews();
}
mTextureView = null;
mTextureView = new GSYTextureView(getContext());
mTextureView.setSurfaceTextureListener(this);
mTextureView.setRotation(mRotate);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
mTextureViewContainer.addView(mTextureView, layoutParams);
}
···
//把Surface丢给视频播放管理
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mSurface = new Surface(surface);
GSYVideoManager.instance().setDisplay(mSurface);
}
//告诉视频播放渲染画面销毁了
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
GSYVideoManager.instance().setDisplay(null);
surface.release();
return true;
}
//这里其实就有播放管理器的分发保存的逻辑需要注意
GSYVideoManager.instance().setLastListener(this);
GSYVideoManager.instance().setListener(gsyVideoPlayer);
效果GIF(比较大):

传闻每一个Activity都有一个com.android.internal.R.id.content,它默默的包括了诸多你塞回去的物体,而且是一个FrameLayout,谷歌有很多它的传说了,我们用它是就是。

既然是FrameLayout,那么我们往他旁边塞东西就好了,这里我们可以在GSYVideoPlayer里面写一个方法,在单击全屏按钮的之后:
在切换的之后可以做一些位移,让播放器的全屏更加友好,下面长代码来袭((/- -)/。深夜码字不易,不知道为什么经常这个之后妈妈的看法很大啊。
Constructor<GSYBaseVideoPlayer> constructor = (Constructor<GSYBaseVideoPlayer>) GSYBaseVideoPlayer.this.getClass().getConstructor(Context.class);
final GSYBaseVideoPlayer gsyVideoPlayer = constructor.newInstance(getContext());
//记录新创建的这个video的id,在返回的时候通过它销毁
gsyVideoPlayer.setId(FULLSCREEN_ID);
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
final int w = wm.getDefaultDisplay().getWidth();
final int h = wm.getDefaultDisplay().getHeight();
//设置黑色背景,自动充满全屏
FrameLayout.LayoutParams lpParent = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
FrameLayout frameLayout = new FrameLayout(context);
frameLayout.setBackgroundColor(Color.BLACK);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//如果5.0的话,先让播放器出现的位置和列表中一直,再样式一会执行到屏幕中间的过度效果
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(getWidth(), getHeight());
lp.setMargins(mListItemRect[0], mListItemRect[1], 0, 0);
frameLayout.addView(gsyVideoPlayer, lp);
vp.addView(frameLayout, lpParent);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
TransitionManager.beginDelayedTransition(vp);
resolveFullVideoShow(context, gsyVideoPlayer, h, w);
}
}, 300);
} else {
//5.0一下直接显示
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(getWidth(), getHeight());
frameLayout.addView(gsyVideoPlayer, lp);
vp.addView(frameLayout, lpParent);
resolveFullVideoShow(context, gsyVideoPlayer, h, w);
}
//设置全屏逻辑播放器的状态,动态及添加播放view
gsyVideoPlayer.setUp(mUrl, mCache, mObjects);
gsyVideoPlayer.setStateAndUi(mCurrentState);
gsyVideoPlayer.addTextureView();
//添加
GSYVideoManager.instance().setLastListener(this);
GSYVideoManager.instance().setListener(gsyVideoPlayer);
这里运用另外一种实现模式,列表的逻辑播放器只用一个,因为普通的list在滑动的之后会有复用和销毁ijkplayer jar,这会导致视频被释放而停止了,如果你是和今日黄(tou)条一样的视频列表播放效果,滑出屏幕就停止那无所谓。
如果你应该无论如何滑动,视频都在以前的位置播放的话,那么ListVideoUtil适合你,,内部它早已带了全屏,防错位,旋转的诸多逻辑,直接上代码,有兴趣的看DEMO。
listVideoUtil = new ListVideoUtil(this);
//设置列表最外层的布局用于全屏,空FrameLayout
listVideoUtil.setFullViewContainer(videoFullContainer);
//全屏隐藏状态栏,如果有的话
listVideoUtil.setHideStatusBar(true);
···
//在列表中吧列表位置,封面,哪个列表的TAG,列表视频的承载ViewGroup,播放按键传入到Utils中
listVideoUtil.addVideoPlayer(position, imageView, TAG, holder.videoContainer, holder.playerBtn);
holder.playerBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//每次播放都要更新列表让其他的item恢复状态
notifyDataSetChanged();
//设置播放的tag和位置,防止错位
listVideoUtil.setPlayPositionAndTag(position, TAG);
//开始播放
final String url = "http://baobab.wdjcdn.com/14564977406580.mp4";
listVideoUtil.startPlay(url);
}
});
OrientationUtils使用的是OrientationEventListener,通过手机的视角判断应该旋转到什么位置。为什么用它?因为谷歌到的时侯刚好看见,缘分啊懂吗。
这里应该个关注的是手动点击和自动旋转之间的矛盾,主要看代码吧,老婆开始催我了 (ノ益)ノ彡┻━┻。
//判断系统是否开了旋转,是的,这货不需要系统旋转是否开启
boolean autoRotateOn = (android.provider.Settings.System.getInt(activity.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 1);
if (!autoRotateOn) {
if (mIsLand == 0) {
return;
}
}
// 设置竖屏
if (((rotation >= 0) && (rotation <= 30)) || (rotation >= 330)) {
//是否点击导致的
if (mClick) {
if (mIsLand > 0 && !mClickLand) {
return;
} else {
//清除状态
mClickPort = true;
mClick = false;
mIsLand = 0;
}
} else {
//自动旋转
if (mIsLand > 0) {
screenType = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
gsyVideoPlayer.getFullscreenButton().setImageResource(R.drawable.video_enlarge);
mIsLand = 0;
mClick = false;
}
}
}
// 设置横屏
else if (((rotation >= 230) && (rotation <= 310))) {
if (mClick) {
if (!(mIsLand == 1) && !mClickPort) {
return;
} else {
mClickLand = true;
mClick = false;
mIsLand = 1;
}
} else {
if (!(mIsLand == 1)) {
screenType = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
gsyVideoPlayer.getFullscreenButton().setImageResource(R.drawable.video_shrink);
mIsLand = 1;
mClick = false;
}
}
}
// 设置反向横屏
else if (rotation > 30 && rotation < 95) {
if (mClick) {
if (!(mIsLand == 2) && !mClickPort) {
return;
} else {
mClickLand = true;
mClick = false;
mIsLand = 2;
}
} else if (!(mIsLand == 2)) {
screenType = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
gsyVideoPlayer.getFullscreenButton().setImageResource(R.drawable.video_shrink);
mIsLand = 2;
mClick = false;
}
}
}
};
orientationEventListener.enable();

好吧ijkplayer jar,老婆睡了,我偷偷出来了(。)ノ
这个需求曾经让我彻夜难眠,因为IJKPlayer不支持,好吧,没见到那个播放器支持的,和产品争(tuo)论(yan)需(shi)求(jian)之后,最终还是github大法好:AndroidVideoCache。
接入简单,使用简单,你可以趾高气扬的和产品说,这个so easy了。
HttpProxyCacheServer proxy = getProxy();
//注意不能传入本地路径,本地的你还传进来干嘛。
String proxyUrl = proxy.getProxyUrl(VIDEO_URL);
videoView.setVideoPath(proxyUrl);
该项目的原理似乎就是将url链接转换为本地链接 h t t p://127.0.0.1:LocalPort/url,然后它开一个服务器一边下载缓存视频,一边把缓存的数据正常返回给你的播放器,如果早已缓存过的这儿会返回一个本地文件模式。Σ( ° △ °|||)︴曾经的我真的是too young too smiple。
//不要忘记配置activity,所有背景的activity
android:configChanges="orientation|keyboardHidden|screenSize"
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
int lastVisibleItem = firstVisibleItem + visibleItemCount;
//大于0说明有播放
if (GSYVideoManager.instance().getPlayPosition() >= 0) {
//当前播放的位置
int position = GSYVideoManager.instance().getPlayPosition();
//对应的播放列表TAG
if (GSYVideoManager.instance().getPlayTag().equals(ListNormalAdapter.TAG)
&& (position < firstVisibleItem || position > lastVisibleItem)) {
//如果滑出去了上面和下面就是否,和今日头条一样
GSYVideoPlayer.releaseAllVideos();
listNormalAdapter.notifyDataSetChanged();
}
}
}
能看到这里都是真爱啊,我最后问两句,你们会感觉文章太长阅读起来非常费劲吗?
相关文章: Android 列表视频的全屏、自动小窗口优化实践
友情链接:
文/恋猫月亮(简书作者)
原文链接:%20
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/bofangqi/article-121653-2.html
小王子