传统方法
- 调整布局,隐藏多余的控件,让后将播放器设置为全屏大小
- 新开一个Activity或PopupWindow来显示全屏播放器
传统方法的弊端
- 布局复杂,播放器可能嵌套在Fragment或TabLayout等元素里面,难以调整为全屏
- 布局调整代码常常极为繁琐,难以编写和阅读
- 新开Activity或PopupWindow,实际是两个播放器对象,所有初始化工作要重新开始,并且需要一段时间来加载视频,本身Activity属于重量级组件,编写的代码比较多,而且流畅度也相对较差
优雅的解决方案
- 我们平时加载的layout文件,其实不是Activity控件树的根节点,layout文件也是被放在一个ContentFrameLayout中,它实际也是个FrameLayout,我们暂把它称为ContentView
- 由于Activity的ContentView是全屏的,而且是FrameLayout,我们只需直接将播放器加入到这个布局中,就可以实现全屏效果了,当然,屏幕还要翻转为横屏
- 这样我们就有了一个非常简单的解决方案,将播放器从父容器中移除,然后再添加到ContentView中,退出全屏模式时,再从ContentView中移除,添加回父容器即可
- 为了方便将播放器还原回父容器,我们可以用一个FrameLayout将播放器包裹起来,用FrameLayout作为播放器的父容器。用FrameLayout包裹最大的优势就是,添加移除控件很方便。将播放器从FrameLayout中移除后,FrameLayout仍然占据着播放器的空间,这样整个Activity布局仍然没有任何不变。如果直接将播放器放在LinearLayout等其它布局中,当播放器移除时,其它控件就会挤占播放器的空间,造成界面错乱
方案弊端
- 有些播放器控件,不能正确处理屏幕翻转,尺寸改变,控件重新绑定父容器等情景
- 但是这个弊端本质是播放器缺陷,就算使用其它方案,也会遇到这个问题
- 对于这类播放器,我们可以重建一个播放器对象放到ContentView中,还原时再重建一个播放器放回FrameLayout
- 采用重建对象的方式,我们需要保存播放进度,在全屏切换时还原进度
参考代码
以上已经给出了完整思路,已经足够大家自己动手完成整个功能 此处代码仅供参考,由于是自己的项目,大量使用了工具类,无法直接使用 如果有功能不清楚如何实现的,可以参考最后的源码
@SuppressWarnings("all")
public class StartActivity extends CommonActivity {
@BindView(R.id.view)
View view;
ViewGroup parent;
ViewGroup.LayoutParams layoutParams;
@Override
protected void create() {
setContentView(R.layout.activity_test);
Views.viewBinding(this, ctx);
requestAllPermissionWithCallback();
}
@Override
protected void onPermissionOk() {
//获得父容器和初始布局参数
parent = (ViewGroup) view.getParent();
layoutParams = view.getLayoutParams();
//全屏切换原理是将View从Parent中移除,添加到Window的ContentView中,并铺满ContentView
//Parent和ContentView都是FrameLayout,移除添加子节点,不会影响到其它控件位置
//屏幕切换不会立刻生效,因此要布局切换代码要延时执行,否则会导致布局计算错误,性能越差的机子需要的延时时间越长
//屏幕切换需要在AndroidManifest里面设置以下选项,否则窗口重建,会导致View移除添加代码报错
//android:configChanges="orientation|screenSize|keyboard|keyboardHidden"
onClick(view, () -> {
boolean horizontal = isHorizontalScreen();
//全屏
if (!horizontal) {
setFixedOrientation(Values.ORIENTATION.ORIENTATION_LANDSCAPE);
postLater(() -> {
ViewGroup activityRootView = Views.getRootView(this);
Views.detachFromParent(view);
Views.attachAndFill(activityRootView, view);
immersiveMode();
}, 200);
}
//还原
else {
setFixedOrientation(Values.ORIENTATION.ORIENTATION_PORTRAIT);
postLater(() -> {
Views.detachFromParent(view);
Views.attachAndLayout(parent, view, layoutParams);
exitImmersiveMode(true);
}, 200);
}
});
}
}
源码下载
安卓播放器全屏切换.zip