-
Notifications
You must be signed in to change notification settings - Fork 121
超级播放器实现原理概述
ZERO edited this page Apr 4, 2019
·
3 revisions
- 基于腾讯云 LiveAV SDK 播放器 TXVodPlayer 、 TXLivePlayer 封装
- 代码开源,采用 MVC 结构。代码结构清晰,易于修改定制。
- 实现超级播放器的核心 View ,采用 MVC 模式实现逻辑解耦
- 有三个 Controller 对 SuperPlayerView 进行管理,分别是:TCVodControllerLarge、TCVodControllerSmall、TCVodControllerFloat
- TCVodControllerLarge 管理全屏状态时候的播放
- TCVodControllerSmall 管理小屏状态时候的播放
- TCVodControllerFloat 管理悬浮状态时候的播放
- SuperPlayerView 暴露的回调
- onStartFullScreenPlay、onStopFullScreenPlay 实现全屏播放的关键,实现其他 View 隐藏,实现全屏播放
- onStartFloatWindowPlay 开始悬浮模式播放的回调
- onClickFloatCloseBtn 悬浮模式下点击 x 按钮的回调,可以实现自己的逻辑
- onClickSmallReturnBtn 小窗模式下点击 < 返回的回调,可以实现自己的逻辑
egg.
@Override
public void onStartFullScreenPlay() {
// 隐藏其他元素实现全屏
mLayoutTitle.setVisibility(GONE);
if (mIvAdd != null) {
mIvAdd.setVisibility(GONE);
}
}
@Override
public void onStopFullScreenPlay() {
// 恢复原有元素
mLayoutTitle.setVisibility(VISIBLE);
if (mIvAdd != null) {
mIvAdd.setVisibility(VISIBLE);
}
}
@Override
public void onClickFloatCloseBtn() {
// 点击悬浮窗关闭按钮,那么结束整个播放
mSuperPlayerView.resetPlayer();
finish();
}
@Override
public void onClickSmallReturnBtn() {
// 点击小窗模式下返回按钮,开始悬浮播放
showFloatWindow();
}
@Override
public void onStartFloatWindowPlay() {
// 开始悬浮播放后,直接返回到桌面,进行悬浮播放
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
}
SuperPlayerView小窗模式下仅仅占用一小块地方,点击后是如何实现全屏播放的?
- 利用反射构造铺满的LayoutParams
try {
// 依据上层Parent的LayoutParam类型来实例化一个新的fullscreen模式下的LayoutParam
Class parentLayoutParamClazz = getLayoutParams().getClass();
Constructor constructor = parentLayoutParamClazz.getDeclaredConstructor(int.class, int.class);
mLayoutParamFullScreenMode = (ViewGroup.LayoutParams) constructor.newInstance(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
} catch (Exception e) {
e.printStackTrace();
}
会利用反射回去父类的LayoutParams
, 然后宽高设置MATCH_PARENT
,备用。
- 外部实现
onStartFullScreenPlay
回调,开始全屏播放的时候,将其他元素全部隐藏
@Override
public void onStartFullScreenPlay() {
mLayoutTitle.setVisibility(GONE);
if (mIvAdd != null) {
mIvAdd.setVisibility(GONE);
}
}
-
SuperPlayerView
设置步骤1准备的全屏LayoutParams
//请求全屏模式
if (requestPlayMode == SuperPlayerConst.PLAYMODE_FULLSCREEN) {
TXCLog.i(TAG, "requestPlayMode FullScreen");
if (mLayoutParamFullScreenMode == null)
return;
removeView(mVodControllerSmall);
addView(mVodControllerLarge, mVodControllerLargeParams);
setLayoutParams(mLayoutParamFullScreenMode);
rotateScreenOrientation(SuperPlayerConst.ORIENTATION_LANDSCAPE);
if (mPlayerViewCallback != null) {
mPlayerViewCallback.onStartFullScreenPlay();
}
}
SuperPlayerView 是如何实现悬浮播放的?
- 往 WindowManager 直接塞 View 进去
mWindowManager = (WindowManager) mContext.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
mWindowParams = new WindowManager.LayoutParams();
mWindowParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mWindowParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
mWindowParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}
mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mWindowParams.format = PixelFormat.TRANSLUCENT;
mWindowParams.gravity = Gravity.LEFT | Gravity.TOP;
SuperPlayerGlobalConfig.TXRect rect = prefs.floatViewRect;
mWindowParams.x = rect.x;
mWindowParams.y = rect.y;
mWindowParams.width = rect.width;
mWindowParams.height = rect.height;
try {
mWindowManager.addView(mVodControllerFloat, mWindowParams);
} catch (Exception e) {
Toast.makeText(SuperPlayerView.this.getContext(), "悬浮播放失败", Toast.LENGTH_SHORT).show();
return;
}
TXCloudVideoView videoView = mVodControllerFloat.getFloatVideoView();
if (videoView != null) {
if (mCurrentPlayType == SuperPlayerConst.PLAYTYPE_VOD) {
mVodPlayer.setPlayerView(videoView);
} else {
mLivePlayer.setPlayerView(videoView);
}
resume();
}
需要特别注意的是悬浮窗权限