小米开发平台刘海屏、水滴屏 Android O 适配
1. 背景
1.1. 目前已上市的小米 Notch 设备(俗称刘海屏手机)如下,其宽度、高度和形状均略有差异
机型 | model | device | 分辨率 | Notch高度 | Notch宽度 | DPI |
小米8 | MI 8 | dipper | 1080*2248 | 89 | 560 | 440 |
小米8 SE | MI 8 SE | s桌面app打包生成irius | 1080*2244 | 85 | 540 | 440 |
小米8 透明探索版 | MI 8 Explorer Edition | ursa | 1080*2248 | 89 | 560 | 440 |
小米8 屏幕指纹版 | MI 8 UD | equuleus | 1080*2248 | 89 | 560 | 440 |
小米8 青春版 | MI8Lite | platina | 1080*2280 | 82 | 296 | 440 |
小米POCO F1 | POCO F1 | beryllium | 1080*2246 | 86 | 588 | 440 |
红米6 Pro | Redmi 6 Pro | sakura | 1080*2280 | 89 | 352 | 440 |
注:以上设备,由于MIUI调整了DPI值,因此DP值与像素值的转换关系是 1dp = 2.75 px 。
1.2. 含 Notch 往往都是全面屏手机,即屏幕比例可能是18:9、18.7:9 等不同的值
全面屏设备的适配建议详见:https://dev.mi.com/console/doc/detail?pId=1160。
1.3. Android P 提供了 刘海屏的标准适配接口
MIUI 也将在 Android P 上采用标准接口,因此,下文提及的接口仅用于 Android O 上。关于 Android P 的接口说明,详见https://dev.mi.com/console/doc/detail?pId=1341。
1.4. 如下图,为便于说明,我们将顶部区域定义为 Notch 和耳朵区
上述两种屏幕都可以统称为刘海屏,不过对于右侧较小的刘海,业界一般称为水滴屏或美人尖。为便于说明,后文提到的「刘海屏」「刘海区」都同时指代上图两种屏幕。
2. 系统级适配规则
Notch 机型在界面上会带来两个问题:
- 顶部内容会被 Notch 遮挡
- 如何处理耳朵区的显示区域
为了保证绝大部分应用都能正常显示,同时尽可能利用屏幕的显示区域。MIUI System UI 制定了以下全局规则:
- status bar 略高于 Notch 高度,对于应用来说,相当于一个更高的 status bar。
- 当应用显示 status bar 时(如微信首页),允许应用使用耳朵区(背后的逻辑是:因为 status bar 区域本身不可交互,且会显示信号、电池等信息,因此我们假定应用不会在该区域放置重要的内容和可交互的控件)。
- 当应用不显示 status bar 时(如全屏游戏),不允许应用使用耳朵区,系统默认填黑。
- 横屏时,默认均不允许使用耳朵区,系统默认填黑。
- 不允许应用180度倒转显示。
注:上述规则的模拟效果对比图,可以参见文末的附录“Notch 屏系统默认规则介绍”。
3. 开发者适配
系统规则只能解决最基础的可用性问题,在系统规则下,开发者仍需要检查以下内容:
- 检查系统默认规则是否有可用性问题,考虑是否做针对性优化。
- 检查 status bar 的显示策略。重新考虑是否隐藏 status bar
- 尽量避免某些页面显示 status bar,某些页面又隐藏,否则会出现页面跳变的情况(应用的可用高度变了)。
- 检查横屏的情况,确定是否需要利用横屏的Notch,若使用,需兼顾 Notch 出现在左边/右边的情况。
- 检查是否写死了状态栏的高度值。Notch机器状态栏的值是变化的,建议改为读取系统的值(后有相关方法说明)。
- 检查开启「隐藏屏幕刘海」后,应用是否显示异常(详见后文)。
- 检查普通屏幕的显示,保证应用在普通屏幕和 Notch 屏幕下都能正常显示 。
4. 系统接口说明
若开发者对系统规则下的效果不满意,可以调用以下接口,做针对性的优化。
4.1. 如何判断设备为 Notch 机型
系统增加了 property ro.miui.notch,值为1时则是 Notch 屏手机。
SystemProperties.getInt("ro.miui.notch", 0) == 1;
4.2. 如何获取 Notch / 凹口 / 刘海 的高度和宽度(截至2018.6.26)
MIUI 10 新增了获取刘海宽和高的方法,需升级至8.6.26开发版及以上版本。
以下是获取当前设备刘海高度的方法:
int resourceId = context.getResources().getIdentifier("notch_height", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}
以下是获取当前设备刘海宽度的方法:
int resourceId = context.getResources().getIdentifier("notch_width", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}
4.3. Application 级别的控制接口
如果开发者认网页加壳生成app为应用的所有页面统一处理就行,可以使用该接口。在 Application 下增加一个 meta-data,用以声明该应用是否使用耳朵区。示例如下:
<meta-data
android:name="notch.config"
android:value="portrait|landscape"/>
其中,value 的取值可以是以下4种:
"none" 横竖屏都不绘制耳朵区
"portrait" 竖屏绘制到耳朵区
"landscape" 横屏绘制到耳朵区
"portrait|landscape" 横竖屏都绘制到耳朵区
注:一旦开发者声明了meta-data,系统就会优先遵从开发者的声明。
4.4. Window 级别的控制接口
如果开发者希望对特定 Window 作处理,可以使用该接口。 在 WindowManager.LayoutParams 增加 extraFlags 成员变量,用以声明该 window 是否使用耳朵区。
其中,extraFlags 有以下变量:
0x00000100 开启配置
0x00000200 竖屏配置
0x00000400 横屏配置
组合后表示 Window 的配置,如:
0x00000100 | 0x00000200 竖屏绘制到耳朵区
0x00000100 | 0x00000400 横屏绘制到耳朵区
0x00000100 | 0x00000200 | 0x00000400 横竖屏都绘制到耳朵区
控制 extraFlags 时注意只控制这几位,不要影响其他位。可以用 Window 的 addExtraFlags 和 clearExtraFlags 来修改, 这两个方法是 MIUI 增加的方法,需要反射调用。
int flag = 0x00000100 | 0x00000200 | 0x00000400;
try {
Method method = Window.class.getMethod("addExtraFlags",
int.class);
method.invoke(getWindow(), flag);
} catch (Exception e) {
Log.i(TAG, "addExtraFlags not found.");
}
4.5. 状态栏高度获取方法
由于 Notch 设备的状态栏高度与正常机器不一样,因此在需要使用状态栏高度时,不建议写死一个值,而应该改为读取系统的值。
以下是获取当前设备状态栏高度的方法:
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}
4.6. 如何测试和联系我们
使用 小米 8 等任意有刘海的小米设备,升级到 MIUI 10 最新开发版即可(若开发版为Android P,请参见 Android P 的刘海适配文档),支持的机型和下载链接如下(找到对应机型的最新开发版):
- 国内版 ROM:https://www.miui.com/download.html
- 国际版 ROM:http://en.miui.com/download.html
4.7. 如何联系我们
可以邮件给我们的项目组 miuishell@xiaomi.com,会有同事解答相关疑问。
5. “隐藏屏幕刘海”适配
MIUI 针对 Notch 设备,有一个“隐藏屏幕刘海”的设置项(设置-全面屏-隐藏屏幕刘海),具体表现是:系统会强制盖黑状态栏(无视应用的Notch使用声明),视觉上达到隐藏刘海的效果。但会给某些应用带来适配问题(控件/内容遮挡或过于靠边等)。
因此开发者在适配时,还需要检查开启“隐藏屏幕刘海”后,应用的页面是否显示正常。针对有问题的页面,我们建议:
- 通过以下方法获取系统状态栏高度,然后据此调整布局,而不是写死布局:
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}
- 如有需要,可以通过查询以下 Global settings 来确定「隐藏屏幕刘海」是否开启了,然后再作针对性优化。
Settings.Global.getInt(mContext.getContentResolver(), "force_black", 0) == 1
6. 关于 Android P 的适配
由于 Android P 已针对异形屏幕提供了标准的接口,因此 MIUI 在后续升级到 Android P 时,将会完全复用 Android P 的接口和逻辑。不过仍有几点值得注意:
- 由于 MIUI Android O 的接口能力与 Android P 有差异,无法二者完全兼容。所以上述提到的接口,在升级到 Android P 后将不再生效,开发者需要针对 Android P 重新适配,望各位开发者谅解。
- 同时,由于运行 MIUI Android O 的刘海屏设备还会存在好几年,开发者在代码上,仍需要保留对 MIUI Android O 的适配逻辑。
由于 Android P 的接口公布得较晚,我们没法做到和 Android P 完全兼容。给各位开发者造成不便,再次表示歉意。小米刘海屏 Android P 的适配文档详见 https://dev.mi.com/console/doc/detail?pId=1341。
7. 附录 – 系统默认规则的说明
如果开发者未做任何声明,系统也会有一套默认的显示规则,下图说的就是这套规则,增加示意图方便大家理解。
编辑:yimen,如若转载,请注明出处:https://www.yimenapp.com/kb-yimen/12582/
部分内容来自网络投稿,如有侵权联系立删