支持刘海屏

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

刘海屏是指某些设备 显示屏上的一个区域延伸到显示面。这样既能为用户提供全面屏体验,又能为设备正面的重要传感器留出空间。

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

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

一张图片,显示了顶部中间刘海屏的示例
图 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 示例:

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

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

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

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

边角处的刘海可等同于在短边上:

一张图片,显示的是一部带边角刘海屏的设备
图 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 示例:

一张图片,显示了竖屏模式下的 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()

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

    一张图片,显示了内容在全屏模式转换过程中上下移动。
    图 8.内容在转换过程中上下移动的示例。
  • 在沉浸式模式下,在使用窗口坐标与屏幕坐标时应保持谨慎,因为在显示黑边的情况下,您的应用不会占据整个屏幕。由于显示黑边,因此根据屏幕原点得到的坐标与根据窗口原点得到的坐标不再相同。您可以根据需要使用 getLocationOnScreen() 将屏幕坐标转换为视图坐标。下图展示了内容显示黑边时这两种坐标有何不同:

    一张图片,显示了内容显示黑边时窗口坐标与屏幕坐标的对比。
    图 9.内容显示黑边时的窗口坐标与屏幕坐标。
  • 处理 MotionEvent 时,请使用 MotionEvent.getX()MotionEvent.getY(),以避免 类似的坐标问题。请勿使用 MotionEvent.getRawX()MotionEvent.getRawY()

测试您的内容如何呈现

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

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

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

其他资源