支持刘海屏

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

刘海屏是某些设备上延伸到显示表面区域的区域。它可在提供设备正面重要传感器空间的同时,带来全屏体验。

Android 在运行 Android 9(API 级别 28)及更高版本的设备上支持刘海屏。然而,设备制造商也可以在运行 Android 8.1 或更低版本的设备上支持刘海屏。

本文档介绍了如何实现对带刘海屏设备的支持,包括如何处理刘海屏区域,即包含刘海屏的显示表面上的全屏矩形。

An image showing an example of top-center display cutout
图 1. 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 的示例

An image showing content rendering into the cutout area while in portrait mode
图 2. 在竖屏模式下内容渲染到刘海屏区域。

以下图片是设备在横屏模式下使用 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 的示例

An image showing content rendering into the cutout area while in landscape mode
图 3. 在横屏模式下内容渲染到刘海屏区域。

在此模式下,无论窗口是否隐藏系统栏,窗口都会延伸到显示屏短边的刘海屏下方,无论是在竖屏还是横屏模式下。

角落的刘海屏被视为位于短边上

An image showing a device with a corner cutout
图 4. 带有角落刘海屏的设备。

绝不在显示屏刘海屏区域渲染内容

如果您的应用以 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 的示例

An image showing the LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER for portrait
图 5. 竖屏模式下 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 的示例。

以下是横屏模式下使用 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 的示例

An image showing the LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER for landscape
图 6. 横屏模式下 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 的示例。

支持刘海屏的最佳实践

处理刘海屏时,请考虑以下几点

  • 注意 UI 中关键元素的放置位置。不要让刘海屏区域遮挡任何重要文本、控件或其他信息。
  • 不要将需要精细触摸识别的任何交互元素放置或延伸到刘海屏区域。刘海屏区域的触摸灵敏度可能较低。
  • 在可能的情况下,使用 WindowInsetsCompat 检索状态栏高度并确定应用于内容适当的内边距。避免硬编码状态栏高度,因为这可能导致内容重叠或被剪裁。

    An image showing content cut at the top for improper insets setup
    图 7. 使用 WindowInsetsCompat 避免内容重叠或被剪裁。
  • 使用 View.getLocationInWindow() 来确定您的应用使用了多少窗口空间。不要假设应用使用了整个窗口,也不要使用 View.getLocationOnScreen()

  • 如果您的应用需要在沉浸模式之间切换,请使用 alwaysshortEdgesnever 刘海屏模式。默认的刘海屏行为可能导致您的应用内容在系统栏存在时渲染在刘海屏区域中,但在沉浸模式下则不会。这会导致内容在过渡期间上下移动,如下例所示。

    An image showing content moving up and down during transitions.
    图 8. 过渡期间内容上下移动的示例。
  • 在沉浸模式下,使用窗口坐标和屏幕坐标时要小心,因为当内容被限制在黑边内时,您的应用不会使用整个屏幕。由于黑边,屏幕原点坐标与窗口原点坐标不同。您可以通过使用 getLocationOnScreen() 根据需要将屏幕坐标转换为视图坐标。下图显示了内容被限制在黑边内时坐标的不同之处

    An image showing window versus screen coordinates when content is letterboxed.
    图 9. 内容被限制在黑边内时的窗口坐标与屏幕坐标。
  • 处理 MotionEvent 时,使用 MotionEvent.getX()MotionEvent.getY() 来避免类似的坐标问题。不要使用 MotionEvent.getRawX()MotionEvent.getRawY()

测试您的内容渲染效果

测试您应用的所有屏幕和体验。如果可能,在具有不同刘海屏类型的设备上进行测试。如果您没有带刘海屏的设备,可以在任何运行 Android 9 或更高版本的设备或模拟器上通过以下方式模拟常见的刘海屏配置

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

    An image showing how to simulate a display cutout in the emulator
    图 10. 用于测试内容渲染效果的开发者选项。

其他资源