Android刘海屏适配
全屏模式下刘海屏黑边(内容区域下挫)问题,支持国国内 华为,小米,OPPO/VIVIO 非原生9.0系统的刘海屏
- 刘海屏是Android9.0之后才支持的 详见源码 android.view.DisplayCutout.class
- 国内主流手机也有刘海屏,官方有相关的刘海屏适配文档,这里提供一个工具类Util 可能更新不及时,仅供参考
- 最终效果是刘海屏不遮挡内容区域,支持旋转,支持国内主流手机。如下
1. 设置全屏
Window window = getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
2. 设置沉浸式状态栏
// 隐藏虚拟按钮 可选 SYSTEM_UI_FLAG_HIDE_NAVIGATION
int flag = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
int visibility = window.getDecorView().getSystemUiVisibility();
visibility |= flag;
window.getDecorView().setSystemUiVisibility(visibility);
3. 让内容延伸至刘海屏区域
3.1 判断是否是刘海屏
注意,判断方法需要放到获取需要在view绑定到window之后,否则拿不到。建议在Activity.onAttachedToWindow()中处理
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
// 判断是否有刘海区域
if(国内主流手机){
// Utils 工具类中有判断是否是刘海屏,并设置全屏的处理办法
}else{
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
Window window = getWindow();
DisplayCutout displayCutout = window.getDecorView().getRootWindowInsets().getDisplayCutout();
if(displayCutout != null){
// 有刘海屏
Log.e("displayCutout","Rect " + displayCutout.getBoundingRects());
Log.e("displayCutout","Rect " + displayCutout.getSafeInsetLeft());
Log.e("displayCutout","Rect " + displayCutout.getSafeInsetTop());
Log.e("displayCutout","Rect " + displayCutout.getSafeInsetRight());
Log.e("displayCutout","Rect " + displayCutout.getSafeInsetBottom());
// 3.2 让内容延伸至刘海区域
// 3.3 刘海屏遮挡的区域下沉
}
}
}
}
3.2 让内容延伸至刘海屏区域
/**
* public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0; // 内容下移,非全屏模式不受影响
* public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1; // 允许内容延伸进入刘海区域
* public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2; // 不允许内容进入刘海屏区域
*/
WindowManager.LayoutParams layoutParams = window.getAttributes();
layoutParams.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
3.3 刘海屏遮挡的区域下挫/下沉
这里有两种方案,根容器设置padding or 修改刘海屏遮挡的空间的位置
- 根布局设置padding 整体的内容区域下沉,此种情况,需要在根布局设置background
// 整体的内容区域(根容器)下沉,将背景图做为根容器背景
findViewById(R.id.root_layout).setPadding(
displayCutout.getSafeInsetLeft(),
displayCutout.getSafeInsetTop(),
displayCutout.getSafeInsetRight(),
displayCutout.getSafeInsetBottom());
- 特定的控件设置padding or margin (设置距离顶部的距离)
View view = findViewById(R.id.cut_clickable_ll);
FrameLayout.LayoutParams cutLayoutParams = (FrameLayout.LayoutParams) view.getLayoutParams();
cutLayoutParams.topMargin = displayCutout.getSafeInsetTop();
view.setLayoutParams(cutLayoutParams);
小米vivo/oppo判断刘海屏并适配工具类Utils