设计适用于可折叠设备的应用

可折叠设备处于部分折叠状态,显示设备正面。

Android 10(API 级别 29)添加了更多对可折叠设备的支持。

设备展开时屏幕会变大,这可以提高设备的易用性:

  • 通常,屏幕越大,体验的沉浸感越强
  • 借助多窗口模式,用户可以同时处理多个任务

折叠和展开设备可以更改屏幕的尺寸、密度或宽高比。在 Android 开发中,这并不是一个新问题;在不涉及可折叠设备的用例中,这也是一个突出的问题,例如:

  • 在手机和平板电脑的竖屏和横屏之间切换
  • 在桌面模式下调整 Android 应用在 Chrome 操作系统上的大小
  • 使用具有多个屏幕的设备

本页介绍了旨在确保应用可与各种可折叠设备完美配合使用的最佳做法。

此外,不妨阅读涉及可折叠设备支持的 Android 10 变更摘要。

应用连续性

在可折叠设备上运行时,应用可以自动从一个屏幕转换到另一个屏幕。转换完成后,应用应该以相同的状态在同一位置恢复,并且当前的任务应该可以继续无缝执行。

可折叠设备向外折叠的动画。

由于系统会在设备折叠或展开转换过程中触发配置更改,因此应用应该保存界面状态并很好地支持配置更改

注意:可折叠设备可以通过多种方式折叠,例如向内折叠(屏幕折叠在设备内)或向外折叠(屏幕外包着设备)。

使应用尺寸可调整

确保应用能够在多窗口模式下运行,并且屏幕尺寸可动态调整。为了最大限度地与应用可能会遇到的任何设备外形规格和环境(例如,可折叠设备、桌面模式或可自由调整的窗口)兼容,请在项目清单文件的 <application><activity> 部分中设置 resizeableActivity=true。 请在分屏模式下或使用可折叠设备模拟器测试应用的行为。

如果应用设置了 resizeableActivity=false,则不支持多窗口模式。系统可能仍会调整应用的尺寸或将其置于多窗口模式,但为了实现兼容性,会对应用中的所有组件(包括所有 activity 和服务)应用同一配置。在某些情况下,重大变更(例如,屏幕尺寸更改)可能会重启进程,而不是更改配置。

例如,以下 activity 设置了 resizableActivity=false 以及 maxAspectRatio。设备展开时,系统会将应用置于兼容模式,以此保持 activity 配置、大小和宽高比。

可折叠设备,显示的应用在屏幕展开后只填充了部分区域。

如果您通过设置 resizeableActivity=false 来停用多窗口模式,但仍希望支持应用连续性,请将以下元数据添加到清单文件的 <application> 元素中:

<meta-data
    android:name="android.supports_size_changes" android:value="true" />

如果 supports_size_changes 为 true,当用户折叠或展开设备时,activity 就会采用支持窗口大小更改的方式来应用任何已更改的配置。

如果您未设置 resizeableActivity(或将其设置为 true),系统会假定应用完全支持多窗口模式,且应用尺寸可调整。

请注意,某些 OEM 可能会实现这样一种功能:每当 activity 的显示区域发生更改时,会在屏幕上添加一个较小的重启图标。这样一来,用户将有机会在新配置中重启 activity。

使用 WindowManager

与不可折叠设备一样,可折叠设备也支持各种窗口模式。

如需在可折叠设备上正确显示应用边界(不论采用何种窗口模式),请使用以下 WindowManager 方法:

Jetpack WindowManager 库的 computeMaximumWindowMetrics()computeCurrentWindowMetrics() 方法提供了相同的功能,且最低可与 API 级别 14 的版本兼容。

可折叠模式

可折叠设备要么采用一块折叠屏,要么是由合页将屏幕分成两部分(通常是对半分开)。带合页的设备可能具有在合页后跨越内容的功能,例如处于跨越模式的 Microsoft Surface Duo。某些设备可以采用半折叠配置,也可以采用其他折叠状态,例如 Samsung 的 Flex 模式

Jetpack WindowManager库可让您以一种与设备无关的方式对设备模式、配置更改和显示功能作出反应。如需了解详情,请参阅这篇博文(Support new form factors with the new Jetpack WindowManager library,使用新的 Jetpack WindowManager 库支持新型设备)。

折叠状态

可折叠设备可以支持如下所示的折叠状态,它们对应于 FoldingFeature 状态常量 FLATHALF_OPENEDFoldingFeature 类是 Jetpack WindowManager 库的一部分。FoldingFeature 可以识别采用合页或一块折叠屏的设备。FoldingFeature 可以实现 DisplayFeature 接口(随着设备生态系统的持续发展,可由新的屏幕类型来实现)。

纵向可折叠设备完全打开。
展平
桌面折叠状态下半打开的纵向可折叠设备。
半开
(桌面折叠状态)

使用 FoldingFeature 类检索设备折叠状态。您可以直接查看以下状态:

或者,您也可以使用以下属性来提抽象出叠设备的状态:

使用这些属性可识别不同的折叠状态,例如桌面模式(合页或折叠边为横向)或图书模式(合页或折叠边为纵向):

private fun isTableTopMode(foldFeature: FoldingFeature) =
        foldFeature.state == FoldingFeature.State.HALF_OPENED &&
            foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL

private fun isBookMode(foldFeature: FoldingFeature) =
        foldFeature.state == FoldingFeature.State.HALF_OPENED &&
            foldFeature.orientation == FoldingFeature.Orientation.VERTICAL

通过从 WindowInfoRepository 类中提供的 windowLayoutInfo Kotlin Flow 收集事件,FoldingFeature 状态如有任何更改,您都会收到通知:

val windowInfoRepository = windowInfoRepository()
lifecycleScope.launch(Dispatchers.Main) {
    // The block passed to repeatOnLifecycle is executed when the lifecycle
    // is at least STARTED and is cancelled when the lifecycle is STOPPED.
    // It automatically restarts the block when the lifecycle is STARTED again.
    lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
        // Safely collects from windowInfoRepository when the lifecycle is
        // STARTED and stops collection when the lifecycle is STOPPED.
        windowInfoRepository.windowLayoutInfo
            .collect { newLayoutInfo ->
                // Check newLayoutInfo.displayFeatures to see if the
                // feature list includes a FoldingFeature, then check
                // the feature's data.
            }
    }
}

Jetpack WindowManager 还提供了 WindowInfoRepositoryCallbackAdapter,这是 WindowInfoRepository 的一个 Java 兼容接口。此适配器通过 addWindowLayoutInfoListener 在应用中注册回调来接收更新。

如需停止接收更新,请使用 removeWindowLayoutInfoListener 移除此回调。

此回调会接收 WindowLayoutInfo 对象中的数据,其中包含窗口显示功能的列表。使用 displayFeatures 属性获取相关信息:

class LayoutStateChangeCallback implements Consumer<WindowLayoutInfo> {
    @Override
    public void accept(WindowLayoutInfo windowLayoutInfo) {
      // Check windowLayoutInfo.displayFeatures to see if the
      // feature list includes a FoldingFeature, then check
      // the feature's data.
    }
}

GitHub 上提供了如何使用和测试这些功能的示例。

合页角度

从 Android 11 开始,在以下情况下,在采用合页式屏幕的设备上运行的应用可以确定合页角度:设备装有传感器,可以提供 TYPE_HINGE_ANGLE 值,并报告 SensorEvent 以提供合页角度的角度值。您可以使用这些测量值在用户操控设备时执行精细的动画显示。

尽管对于某些类型的应用(例如启动器和壁纸)而言,知道确切的合页角度会很有用,但大多数应用都应该使用 Jetpack WindowManager 库来检索设备折叠状态,这是因为目前市场上有许多不同的设备配置(未来还会出现更多配置),因而响应折叠状态会更加可靠。

测试

若要备妥应用,使其适合在可折叠设备上使用,您应该测试应用对以下各项的响应情况:

  • 配置更改
  • 多窗口模式和多项恢复
  • 调整大小和新的屏幕宽高比

可折叠模拟器

Android 开源项目 (AOSP) 包含各种设备模拟器,用于模拟可折叠设备的功能。

借助 Android Studio 的 Android 虚拟设备 (AVD) 管理器,您可以轻松地使用可折叠设备模拟器来测试您的应用。

可折叠设备在设备模拟器中打开和关闭的动画。

可折叠设备模拟器。

多屏幕

借助强制使用桌面开发者选项,您可以在所有辅助屏幕上启用系统装饰支持。强制使用桌面模式还会在辅助屏幕(而非默认屏幕)上显示鼠标指针。当与启用可自由调整的窗口开发者选项结合使用时,强制使用桌面模式会模拟提供多窗口模式和窗口大小调整功能的桌面体验。

您可以通过模拟屏幕或在设备支持 HDMI 或 DisplayPort over USB-C 的情况下通过有线连接使用多个屏幕。

手机显示了一个对话框,供您选择各种类型的模拟辅助屏幕。

模拟屏幕。