写点什么

号外!号外!全网第一手 Android P 刘海屏适配大揭秘,android 屏幕适配终极解决方案

用户头像
Android架构
关注
发布于: 刚刚

1.2.需要适配的情况

Android P 版本提供了统一的刘海屏方案和三方适配刘海屏方案:


  • 对于有状态栏的页面,不会受到刘海屏特性的影响

  • 全屏显示的页面,系统刘海屏方案会对应用界面做下移处理,避开刘海区显示

  • 已经适配 Android P 应用的全屏页面可以通过谷歌提供的适配方案使用刘海区,真正做到全屏显示。

2. 搭建环境

在手边没有对应系统的设备的时候,模拟器是一条不错的路,最近 Google 也发布了 Android P 的模拟器,还有一个办法就是找一些支持真机云测的平台,例如华为的云测平台,也是一个解决方案,不过没有本地模拟机这么便捷。

2.1.华为终端开放实验室

2.2.本地模拟器

选择 Android P 的模拟器,有


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


需要自己更新 SDK,下载更新就好。



刘海的凹槽区域,大部分是为了给摄像头或者其他传感器留出区域。而在没有刘海的设备或者模拟器上,可以通过开发者选项里的 “Simulate a display with a cutout”,开启刘海屏的支持。



Android P 模拟器自带四种刘海屏的模式,分别为:“None”、“Narrow display cutout”、“Tall display cutout”和“Wide display cutout”。如下图所示:





3. 兼容性影响

上面也讲清楚了,刘海屏的切割区域,都存在于状态栏上,所以在有状态栏的页面上,是无需我们特殊处理的,系统会帮我们处理好。


而对于全屏的页面,就需要单独的处理了。我这里,简单做了一个全屏页面,每个横条都是等宽的这样能看到布局上的差异。





一个全屏的页面,当没有支持刘海屏又碰到了刘海屏,会导致 UI 下沉,如果这不是一个列表的布局,底部的控件就会被遮挡。


还有一些被刘海遮挡区域的效果,其实主要是依赖 UI 设计师来规避了,不要在可能出现刘海切割的地方,设计可操作的区域,影响用户操作。

4. 官方刘海屏适配

说那么多,最终我们还是需要用技术的方式来适配刘海屏。Android P 的刘海屏,是有标准的 Api 来进行适配,而对于一些厂商自己的刘海屏设备,例如:OPPO R15,就需要遵循它的开发文档进行单独适配。


Android P 为最新的刘海屏,提供了专门的 Api 来支持:DisplayCutout

4.1.开启刘海屏

在非刘海屏 P 版本手机可以开启模拟刘海屏调试的功能


  • 在开发人员选项屏幕中,向下滚动到绘图部分,然后点击“模拟具有凹口的显示屏”设置项

  • 选择刘海尺寸信息


如下图所示:



4.2.适配刘海屏

在刘海屏调试打开之后,浏览应用的所有页面,测试所有遮挡问题,或者是下移导致的问题,对有问题的页面进行布局适配。适配方案如下:


Google 提供的适配方案,可以设置是否在全屏模式下,使用刘海屏的区域。


// 谷歌官方提供的默认适配刘海屏 val attrib = window.attributesattrib.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS


新的布局属性 layoutInDisplayCutoutMode 包含三种可选的模式,分别为:


// 窗口声明使用刘海区域 public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1;// 默认情况下,全屏窗口不会使用到刘海区域,非全屏窗口可正常使用刘海区域 public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0;// 声明不使用刘海区域 public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2;

4.3.刘海屏的高度

在全屏模式下,我们的应用页面背景充满整个屏幕显示,控件和文字等关键信息布局在状态栏以外的区域,以保证关键信息不会出现遮挡(谷歌要求:凹槽高度和刘海高度要保持一致)。我们需要有办法获取到刘海屏凹槽的高度,才可以做到设计和布局的时候,留出安全距离。

4.3.1. 获取刘海尺寸信息接口

Android P 已经预留出了标准的测量刘海屏凹槽的 Api:DisplayCutout



刘海屏的凹槽,就在屏幕的中间,所以只有**getSafeInsetTop()方法返回的结果,是我们需要的,而其他的 getSafeInsetXXX()**方法,直接返回的是 0。代码如下所示:


btn_always.postDelayed(Runnable {


val displayCutout = btn_always.rootWindowInsets.displayCutoutif (null == displayCutout) {Log.e(TAG, "displayCutout is empty")return@Runnable}Log.i(TAG, "SafeInsetBottom:" + displayCutout.safeInsetBottom);Log.i(TAG, "SafeInsetLeft:" + displayCutout.safeInsetLeft);Log.i(TAG, "SafeInsetRight:" + displayCutout.safeInsetRight);Log.i(TAG, "SafeInsetTop:" + displayCutout.safeInsetTop);


}, 100)


输出结果为:


SafeInsetBottom:0SafeInsetLeft:0SafeInsetRight:0SafeInsetTop:84

4.3.2. 获取系统状态栏高度接口

获取刘海屏的高度之后,我们还要获取系统状态栏的高度,代码如下:


fun getStatusBarHeight(context: Context): Int {


var result = 0


val resourceId = context.resources.getIdentifier("status_bar_height", "dimen", "android")if (0 < resourceId) {result = context.resources.getDimensionPixelOffset(resourceId)}


return result}

5. 其他厂商刘海屏适配

像华为、Oppo 和 Vivo 这样的厂商,实现刘海屏的方式,也并不是按照 Android P 的标准做的,它完全是自己修改了刘海屏的实现方式。不过他们是会提供完备的适配文档,这就需要我们直接阅读他们提供的开发文档来进行适配。各个厂商的刘海屏适配参考如下:


5.1.华为

华为提供了刘海屏 Api,可以通过反射的方式调用。

5.1.1. 判断是否刘海屏接口

代码如下:


/**


  • 判断是否是华为刘海屏

  • @param context 上下文对象

  • @return true:是刘海屏;false:非刘海屏*/fun hasNotchInScreen(context: Context): Boolean {var ret = falsetry {val cl = context.getClassLoader()val HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil")val method = HwNotchSizeUtil.getMethod("hasNotchInScreen")ret = method.invoke(HwNotchSizeUtil) as Boolean


} catch (e: ClassNotFoundException) {Log.e(TAG, "hasNotchInScreen ClassNotFoundException")} catch (e: NoSuchMethodException) {Log.e(TAG, "hasNotchInScreen NoSuchMethodException")} catch (e: Exception) {Log.e(TAG, "hasNotchInScreen Exception")} finally {return ret}}

5.1.2. 获取刘海尺寸信息接口

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
号外!号外!全网第一手Android P刘海屏适配大揭秘,android屏幕适配终极解决方案