产品资讯

Android 设备可无缝扩展到外接显示屏

阅读用时:7 分钟
Francesco Romano
开发者关系工程师,Android

我们很高兴地宣布,Android 在拉近移动设备和桌面设备之间的距离方面取得了重大里程碑:连接的显示屏支持已随 Android 16 QPR3 版本正式版发布!

正如 Google I/O 2025 上展示的那样,连接的显示屏可让用户将 Android 设备连接到外部显示器,并立即访问桌面窗口化模式环境。应用可以在自由式窗口或最大化窗口中使用,用户可以像在桌面操作系统上一样同时处理多项任务。

Google 和 Samsung 携手合作,为 Android 生态系统中运行 Android 16 的设备带来顺畅而强大的窗口化模式体验,让用户在连接到外部显示屏时也能畅享这一体验。
现在,用户可以将受支持的 Pixel 和 Samsung 手机连接到外部显示器,在受支持的设备* 上普遍使用此功能,从而获得新的机会来打造更具吸引力、更高效的应用体验,并使其能够适应各种设备规格。

运作方式

当受支持的 Android 手机或可折叠设备连接到外部显示屏时,连接的显示屏上会启动新的桌面会话。

连接的显示屏上的体验与桌面设备上的体验类似,包括一个显示活跃应用的任务栏,用户可以固定应用以便快速访问。用户可以在连接的显示屏上以可自由调整大小的窗口并排同时运行多个应用。

materialDisplay.gif

手机连接到外接显示屏,显示屏上显示桌面会话,同时手机保持自身状态。

当支持桌面窗口化模式的设备(例如 Samsung Galaxy Tab S11 等平板电脑)连接到外部显示屏时,桌面会话会扩展到这两个显示屏,从而解锁更广阔的工作空间。这两个显示屏相当于一个无缝衔接的整体,应用窗口、内容和光标都可以在两屏之间自由移动。

materialDisplay2.gif

平板电脑连接到外接显示屏,桌面会话扩展到这两个显示屏。

这又有什么关联了?

在 Android 16 QPR3 版本中,我们最终确定了窗口化行为、任务栏互动和输入兼容性(鼠标和键盘),这些因素共同定义了连接的显示屏体验。我们还添加了 兼容性处理,以便在切换显示屏时缩放窗口并避免应用重启。


如果您的应用是根据自适应设计原则构建的,那么它将自动具有桌面版的外观和风格,用户会感觉非常熟悉。如果应用锁定为竖屏模式或假定为仅限触控的界面,现在是时候进行现代化改造了。

具体而言,请注意以下关键最佳实践,以便在外接显示屏上获得最佳应用体验:

  • 请勿假设 Display 对象保持不变:当应用窗口移至外部显示屏或显示配置发生变化时,与应用上下文关联的 Display 对象可能会发生变化。您的应用应妥善处理配置更改事件,并动态查询显示指标,而不是缓存这些指标。
  • 考虑密度配置变化:外部显示屏的像素密度可能与主设备屏幕的像素密度截然不同。请确保您的布局和资源能够正确适应这些变化,以保持界面清晰度和易用性。为布局使用密度无关像素 (dp),提供密度特定的资源,并确保界面可适当缩放。
  • 正确支持外部外围设备:当用户把设备连接到外部显示屏时,通常会营造一个更像桌面设备的使用环境。这常常涉及使用外接键盘、鼠标、触控板、摄像头、麦克风和音箱。改进了对键盘鼠标互动的支持。

利用现代工具打造面向未来的桌面设备

我们提供了多种工具来帮助您打造桌面版体验。我们来回顾一下核心自适应库的最新更新!

新的窗口大小类:大和超大

Jetpack WindowManager 1.5.0 中最大的更新是新增了两个宽度窗口大小类:“大”和“超大”。

窗口大小类是我们官方提供的一组主观的视口划分点,可帮助您设计和开发自适应布局。在 1.5.0 中,我们将此指南的适用范围扩展到超出典型平板电脑尺寸的屏幕。

以下是新的宽度断点:

  • 大:适用于宽度介于 1200dp 和 1600dp 之间的屏幕
  • 超大:宽度 ≥1600dp
windowClasses.png

基于显示宽度的不同窗口大小类别。

在非常大的界面上,简单地放大平板电脑的展开布局并不总是能提供最佳用户体验。例如,电子邮件客户端可能会在“展开”窗口尺寸类中轻松显示两个窗格(邮箱和邮件)。但在超大桌面显示器上,电子邮件客户端可以同时优雅地显示三个甚至四个窗格,例如邮箱、邮件列表、完整邮件内容和日历/任务面板。

如需在项目中包含新的窗口大小类别,只需从 WindowSizeClass.BREAKPOINTS_V2 集中调用该函数,而不是从 WindowSizeClass.BREAKPOINTS_V1 中调用:

  val currentWindowMetrics =
    WindowMetricsCalculator.getOrCreate()
    .computeCurrentWindowMetrics(LocalContext.current)

val sizeClass = WindowSizeClass.BREAKPOINTS_V2
    .computeWindowSizeClass(currentWindowMetrics)

然后,在确定应用至少有这么多空间时,应用正确的布局:

  if(sizeClass.isWidthAtLeastBreakpoint(
    WindowSizeClass.WIDTH_DP_LARGE_LOWER_BOUND)){
    ...
	// Window is at least 1200 dp wide.
}

使用 Jetpack Navigation 3 构建自适应布局

Navigation 3 是 Jetpack 系列的最新成员。Navigation 3 刚刚发布了首个稳定版,是一款功能强大的导航库,旨在与 Compose 搭配使用。

Navigation 3 也是一款出色的工具,可用于构建自适应布局,它允许同时显示多个目的地,并允许在这些布局之间无缝切换。

此系统用于管理应用的界面流程,基于场景。场景是一种同时显示一个或多个目的地的布局。SceneStrategy 用于确定是否可以创建场景。通过将 SceneStrategy 实例链接在一起,您可以针对不同的屏幕尺寸和设备配置创建并显示不同的场景。

对于开箱即用的规范布局(例如列表-详情和辅助窗格),您可以使用 Compose Material 3 Adaptive 库中的场景(可在版本 1.3 及更高版本中使用)。

您还可以通过修改场景配方或从头开始轻松构建自己的自定义场景。例如,假设某个场景并排显示三个窗格:

  class ThreePaneScene<T : Any>(
    override val key: Any,
    override val previousEntries: List<NavEntry<T>>,
    val firstEntry: NavEntry<T>,
    val secondEntry: NavEntry<T>,
    val thirdEntry: NavEntry<T>
) : Scene<T> {
    override val entries: List<NavEntry<T>> = listOf(firstEntry, secondEntry, thirdEntry)
    override val content: @Composable (() -> Unit) = {
        Row(modifier = Modifier.fillMaxSize()) {
            Column(modifier = Modifier.weight(1f)) {
                firstEntry.Content()
            }
            Column(modifier = Modifier.weight(1f)) {
                secondEntry.Content()
            }
            Column(modifier = Modifier.weight(1f)) {
                thirdEntry.Content()
            }
        }
    }

在这种情况下,您可以定义一个 SceneStrategy,以便在窗口宽度足够大且返回堆栈中的条目已声明支持在三窗格场景中显示时,显示三个窗格。

  class ThreePaneSceneStrategy<T : Any>(val windowSizeClass: WindowSizeClass) : SceneStrategy<T> {
    override fun SceneStrategyScope<T>.calculateScene(entries: List<NavEntry<T>>): Scene<T>? {
        if (windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_LARGE_LOWER_BOUND)) {
            val lastThree = entries.takeLast(3)
            if (lastThree.size == 3 && lastThree.all { it.metadata.containsKey(MULTI_PANE_KEY) }) {
                val firstEntry = lastThree[0]
                val secondEntry = lastThree[1]
                val thirdEntry = lastThree[2]


                return ThreePaneScene(
                    key = Triple(firstEntry.contentKey, secondEntry.contentKey, thirdEntry.contentKey),
                    previousEntries = entries.dropLast(3),
                    firstEntry = firstEntry,
                    secondEntry = secondEntry,
                    thirdEntry = thirdEntry
                )
            }
        }
        return null
    }
}

创建 NavDisplay 时,您可以将 ThreePaneSceneStrategy 与其他策略搭配使用。例如,我们还可以添加 TwoPaneStrategy,以便在空间不足以显示三个窗格时并排显示两个窗格。

  val strategy = ThreePaneSceneStrategy() then TwoPaneSceneStrategy()

NavDisplay(..., 
  sceneStrategy = strategy,
  entryProvider = entryProvider { 
    entry<MyScreen>(metadata = mapOf(MULTI_PANE_KEY to true))) { ... }
    ... other entries...
  }
)

如果没有足够的空间来显示三个或两个窗格,我们的两种自定义场景策略都会返回 null。在这种情况下,NavDisplay 会回退为使用 SinglePaneScene 在单个窗格中显示返回堆栈中的最后一个条目。

通过使用场景和策略,您可以为应用添加单窗格、双窗格和三窗格布局!

adaptivepane.gif

一个自适应应用,在宽屏上显示三窗格导航。

请查看相关文档,详细了解如何在 Navigation 3 中使用场景创建自定义布局

独立自适应布局

如果您需要独立布局,Compose Material 3 自适应库可帮助您创建自适应界面,例如列表-详情和支持窗格布局,这些布局可根据窗口大小类别或设备姿态自动调整自身以适应窗口配置。

好消息是,该库已更新为新的断点!从版本 1.2 开始,默认窗格支架指令函数支持“大”和“超大”宽度窗口大小类别。

您只需在 Gradle build 文件中声明要使用新的断点,即可选择启用该功能:

currentWindowAdaptiveInfo(supportLargeAndXLargeWidth = true)

使用入门

探索最新 Android 版本中的关联显示屏功能。在受支持的设备上获取 Android 16 QPR3,然后将其连接到外部显示器,立即开始测试您的应用!

请深入了解有关多显示屏支持窗口管理的更新文档,详细了解如何实施这些最佳实践。

反馈

在我们不断改进关联显示器桌面体验的过程中,您的反馈至关重要。您可以通过我们的官方反馈渠道分享您的想法并报告任何问题。

我们一直致力于让 Android 成为一个多功能平台,能够适应用户与应用和设备互动的多种方式。改进对关联显示屏的支持是朝着这个方向迈出的又一步,我们认为您的用户会喜欢您打造的桌面体验!


*注意:在撰写本文时,Pixel 8、9、10 系列和各种三星设备(包括 S26、Fold7、Flip7 和 Tab S11)均支持连接的显示屏。

作者:

继续阅读