支持刘海屏

试用 Compose 方式
Jetpack Compose 是推荐用于 Android 的界面工具包。了解如何在 Compose 中使用刘海屏。

刘海屏是某些设备上延伸到显示屏表面的一个区域。该模式可实现无边框体验,同时为设备正面的重要传感器留出空间。

Android 支持在搭载 Android 9(API 级别 28)及更高版本的设备上显示刘海屏。不过,设备制造商也可以在搭载 Android 8.1 或更低版本的设备上支持刘海屏。

本文档介绍了如何支持有刘海屏的设备,包括如何使用刘海屏区域,即显示屏上包含刘海屏的无边框矩形。

图片:顶部中央刘海屏示例
图 1. 1 刘海屏。

选择您的应用如何处理刘海区域

如果您不希望内容与刘海区域重叠,通常只需确保您的内容不与状态栏和导航栏重叠即可。如果您要渲染到刘海区域,请使用 WindowInsetsCompat.getDisplayCutout() 检索一个 DisplayCutout 对象,该对象包含每个刘海屏的安全边衬区和边界框。通过这些 API,您可以检查内容是否与刘海屏重叠,以便在需要时重新放置。

您还可以确定内容是否位于刘海区域后面。layoutInDisplayCutoutMode 窗口布局属性用于控制内容在刘海区域的绘制方式。您可以将 layoutInDisplayCutoutMode 设置为以下值之一:

您可以通过编程方式或通过在 activity 中设置样式来设置刘海模式。以下示例定义了将 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 属性应用于 activity 的样式。

<style name="ActivityTheme">
  <item name="android:windowLayoutInDisplayCutoutMode">
    shortEdges <!-- default, shortEdges, or never -->
  </item>
</style>

以下部分更详细地介绍了不同的刘海模式。

默认行为

默认情况下,在未设置特殊标志的竖屏模式下,在有刘海屏的设备上,状态栏的高度会调整为至少与刘海屏一样高,并且您的内容会显示在下方区域。在横屏模式或全屏模式下,您的应用窗口会采用信箱模式,因此您的任何内容都不会显示在刘海区域中。

将内容呈现在短边刘海区域中

对于某些内容(如视频、照片、地图和游戏),在刘海区域中渲染是为用户提供更具沉浸感的全面屏体验的绝佳方式。借助 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES,在纵向和横向模式下,内容都会延伸到屏幕短边上的刘海区域(无论系统栏处于隐藏还是可见状态)。使用此模式时,请确保没有重要内容与刘海区域重叠。

下图是设备的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 示例(处于竖屏模式):

一张图片,显示以竖屏模式将内容呈现到刘海区域中
图 2. 在竖屏模式下将内容渲染到刘海区域中。

下图是设备的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 示例(横屏模式):

图片,显示在横屏模式下将内容呈现到刘海区域
图 3. 在横屏模式下将内容渲染到刘海区域中。

在此模式下,无论窗口是否隐藏系统栏,在竖屏和横屏模式下,窗口都会扩展到显示屏短边上的刘海屏。

边角上的缺口会被视为位于短边:

显示有边角刘海屏的设备的图片
图 4. 带边角刘海屏的设备。

从不将内容呈现在刘海区域中

使用 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 时,不允许窗口与刘海区域重叠。

以下是纵向模式下的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 示例:

显示纵向的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 的图片
图 5. 竖屏模式的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 示例。

以下是横屏模式下的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 示例:

显示横向 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 的图片
图 6. 横屏模式下的 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 示例。

支持刘海屏的最佳做法

使用刘海屏时,请考虑以下事项:

  • 请注意界面中关键元素的放置位置。不要让刘海区域遮盖任何重要的文本、控件或其他信息。
  • 请勿将任何需要精细触摸识别的互动元素放置或延伸到刘海区域。刘海区域中的轻触灵敏度可能要低一些。
  • 如果可能,请使用 WindowInsetsCompat 检索状态栏高度,并确定要对内容的适当内边距。避免对状态栏高度进行硬编码,因为这可能会导致内容重叠或截断。

    图片:因边衬区设置不当而在顶部切割内容
    图 7.使用 WindowInsetsCompat 避免内容重叠或截断。
  • 您可以使用 View.getLocationInWindow() 确定应用使用多少窗口空间。不要假定应用使用了整个窗口,也不要使用 View.getLocationOnScreen()

  • 如果您的应用需要进入和退出沉浸模式,请使用 shortEdgesnever 刘海模式。默认的刘海行为可能会导致应用中的内容在系统栏存在时显示在刘海区域中,但在沉浸模式下则不会。这会导致内容在过渡期间上下移动,如以下示例所示。

    显示内容在过渡期间上下移动的图片。
    图 8.在过渡期间上下移动的内容示例。
  • 在沉浸模式下,请谨慎使用窗口坐标与屏幕坐标,因为您的应用在进入信箱模式时不会占用整个屏幕。由于信箱模式的存在,基于屏幕原点的坐标与基于窗口原点的坐标不同。您可以根据需要使用 getLocationOnScreen() 将屏幕坐标转换为视图的坐标。下图显示了内容为信箱模式时坐标有何不同:

    显示内容为信箱模式时窗口与屏幕坐标的图片。
    图 9.内容采用信箱模式时,窗口坐标与屏幕坐标。
  • 处理 MotionEvent 时,请使用 MotionEvent.getX()MotionEvent.getY() 来避免类似的坐标问题。请勿使用 MotionEvent.getRawX()MotionEvent.getRawY()

测试您的内容如何呈现

测试应用的所有屏幕和体验。如有可能,请在具有不同类型的刘海屏的设备上进行测试。如果您的设备没有刘海屏,您可以执行以下操作,在搭载 Android 9 或更高版本的任何设备或模拟器上模拟常见的刘海屏配置:

  1. 启用开发者选项
  2. 开发者选项屏幕中,向下滚动到绘图部分,然后选择模拟刘海屏
  3. 选择刘海类型。

    该图片显示了如何在模拟器中模拟刘海屏
    图 10.用于测试内容呈现方式的开发者选项。

其他资源