刘海屏是指某些设备 显示屏上的一个区域延伸到显示面。这样既能为用户提供全面屏体验,又能为设备正面的重要传感器留出空间。
Android 在搭载 Android 9(API 级别 28)及更高版本的设备上支持刘海屏。不过,设备制造商也可以在搭载 Android 8.1 或更低版本的设备上支持刘海屏。
本文档介绍如何实现对带刘海屏的设备的支持, 包括如何处理“刘海区域”,即显示面上包含刘海的无边框 矩形。
选择您的应用如何处理刘海区域
如果不希望您的内容与刘海区域重叠,请确保您的内容不与状态栏和导航栏重叠,这样做一般就足够了。如果要将内容呈现到刘海区域中,请使用
WindowInsetsCompat.getDisplayCutout()
来检索 DisplayCutout 对象
,该对象包含每个刘海区域的安全边衬区和边界框。借助这些 API,您可以检查内容是否与刘海重叠,以便在需要时重新定位。
您还可以确定内容是否布局在刘海区域后面。
layoutInDisplayCutoutMode
窗口布局属性控制您的内容如何呈现在刘海区域中。
您可以将 layoutInDisplayCutoutMode 设置为以下值之一:
LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT:当刘海屏包含在系统栏中时,内容会呈现到刘海区域中。否则,窗口不会与刘海屏重叠;例如,内容在横屏模式下显示时可能会显示黑边。如果您的应用以 SDK 35 为目标平台,则对于非浮动窗口,此值会被解读为ALWAYS。LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS:始终允许内容延伸到刘海区域。如果您的应用以 SDK 35 为目标平台,并且在搭载 Android 15 的设备上运行,则这是非浮动窗口确保无边框显示的唯一允许模式。LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES:在竖屏模式和横屏模式下,内容都会呈现到刘海区域中。请勿用于浮动窗口。如果您的应用以 SDK 35 为目标平台,则对于非浮动窗口,此值会被解读为ALWAYS。LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER:内容永远不会呈现到刘海区域中。如果您的应用以 SDK 35 为目标平台,则对于非浮动窗口,此值会被解读为ALWAYS。
您可以通过编程或在 Activity 中设置
样式来设置刘海模式。以下示例定义了一种样式,用于将 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 属性应用到 Activity。
<style name="ActivityTheme"> <item name="android:windowLayoutInDisplayCutoutMode"> shortEdges <!-- default, shortEdges, or never --> </item> </style>
以下部分将更详细地介绍不同的刘海模式。
默认行为
如果您的应用以 SDK 35 为目标平台,并且在搭载 Android 15 的设备上运行,则
LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS是默认行为,并且
LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT会被解读为
LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS对于非浮动窗口。
否则,LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 是默认值。
将内容呈现在短边刘海区域中
如果您的应用以 SDK 35 为目标平台,并且在搭载 Android 15 的设备上运行,则对于非浮动窗口,LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 会被解读为 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS。
如果设置了 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES,则在竖屏模式和横屏模式下,内容都会延伸到显示屏的短边上的刘海区域,而不管系统栏处于隐藏还是可见状态。使用此模式时,请确保没有重要内容与刘海区域重叠。
下图是竖屏模式下设备的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 示例:
下图是横屏模式下设备的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 示例:
在此模式下,无论窗口是否隐藏系统栏,窗口都会在竖屏模式和横屏模式下延伸到显示屏短边上的刘海下方。
边角处的刘海可等同于在短边上:
从不将内容呈现在刘海屏区域中
如果您的应用以 SDK 35 为目标平台,并且在搭载 Android 15 的设备上运行,则对于非浮动窗口,LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 会被解读为 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS。
如果设置了 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER,则不允许窗口与刘海区域重叠。
以下是竖屏模式下的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 示例:
LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 示例。
以下是横屏模式下的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 示例:
LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 示例。
支持刘海屏的最佳做法
使用刘海屏时,请考虑以下几点:
- 注意界面关键元素的位置。不要让刘海区域遮盖任何重要的文本、控件或其他信息。
- 不要将任何需要精细轻触识别的交互式元素放置或延伸到刘海区域。刘海区域中的触控灵敏度可能要比其他区域低一些。
如有可能,请使用
WindowInsetsCompat检索状态栏高度,并确定要对您的内容应用的适当内边距。避免对状态栏高度进行硬编码,因为这样做可能会导致内容重叠或被切断。
图 7.使用 WindowInsetsCompat避免内容重叠或被切断。使用
View.getLocationInWindow()确定应用使用的窗口空间量。不要假设应用正在 使用整个窗口,也不要使用View.getLocationOnScreen()。如果您的应用需要进入和退出沉浸式模式,请使用
always、shortEdges或never刘海模式。默认刘海行为可导致应用中的内容在系统栏存在时呈现在刘海区域中,但在沉浸式模式下则不会。这会导致内容在转换过程中上下移动,如以下示例所示。
图 8.内容在转换过程中上下移动的示例。 在沉浸式模式下,在使用窗口坐标与屏幕坐标时应保持谨慎,因为在显示黑边的情况下,您的应用不会占据整个屏幕。由于显示黑边,因此根据屏幕原点得到的坐标与根据窗口原点得到的坐标不再相同。您可以根据需要使用
getLocationOnScreen()将屏幕坐标转换为视图坐标。下图展示了内容显示黑边时这两种坐标有何不同:
图 9.内容显示黑边时的窗口坐标与屏幕坐标。 处理
MotionEvent时,请使用MotionEvent.getX()和MotionEvent.getY(),以避免 类似的坐标问题。请勿使用MotionEvent.getRawX()或MotionEvent.getRawY()。
测试您的内容如何呈现
测试应用的所有屏幕和体验。如果可以,请在具有不同类型刘海的设备上进行测试。如果您没有带刘海屏的设备,可以在搭载 Android 9 或更高版本的任意设备或模拟器上模拟常见的刘海配置,具体操作步骤如下:
- 启用开发者选项。
- 在开发者选项 屏幕中,向下滚动到绘制 部分,然后选择模拟刘海屏 。
选择刘海类型。
图 10.用于测试内容呈现方式的开发者选项。
其他资源
- LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
- LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
- LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
- LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT