采用网格和 mediaQuery 的桌面姿势布局

4 星评分图标

在可折叠设备上,桌面姿态会将单个屏幕拆分为两个功能性显示区域,这两个区域由物理折叠边(或铰链)分隔开来。 桌面姿态可让您将应用的主要内容(例如视频播放器或游戏画布)放置在上半部分,同时将互动元素(例如媒体控件或控制板)放置在下半部分。

可折叠设备处于桌面姿态,顶部屏幕显示视频内容,底部屏幕显示播放控件。
图 1. 桌面姿势会在实体折叠处拆分内容和互动控件。

最佳做法

如需为应用添加桌面模式支持,请使用 Grid API 定义一个包含两行一列的布局,并应用桌面模式窗口姿势媒体查询。

  • 被动检测桌面模式:使用 mediaQuery 可组合项来观察设备状态。当设备折叠成桌面姿势 (windowPosture == Posture.Tabletop) 时,动态调整布局,而无需重启 activity 或进行复杂的生命周期处理。
  • 使用 Grid 布局结构:在桌面模式下,使用 Grid API(2 rows、1 column)将主要视觉内容清晰地分隔到折叠上方的顶行,并将互动控件分隔到折叠下方的底行。
  • 利用叠加层的隐式 z-index:在标准(非桌面)姿态下,为同一单元格分配多个区域 ID,以将控件叠加在播放器上。Grid 会按声明顺序自动从后到前渲染项。
  • 提供顺畅的过渡:确保在标准全屏布局和桌面姿势之间过渡时,状态和滚动位置得以保留。

所需要素

  • Grid:一种自适应布局容器,可让您在可配置的行和列中放置项,非常适合将内容拆分到不同的屏幕区域。
  • mediaQuery:一种 Jetpack Compose API,用于直接在可组合项中查询应用的当前窗口姿态、大小类别和硬件特征。

步骤

使用 mediaQuery() 查询设备姿态。当设备处于桌面折叠状态时,请将应用的内容排列成一个两行一列的垂直网格,确保主要内容位于顶部,控件位于底部且可供访问。

1. 为桌面模式定义网格配置

在可组合函数内,使用枚举定义布局区域 ID,并为默认姿势和桌面姿势设置 GridConfigurationScope 块。

在 defaultConfig 中,这两个区域都分配给同一个单元格 (row = 1, column = 1)。Grid 使用隐式 z 索引,其中布局中稍后声明的可组合项会渲染在较早声明的可组合项之上,从而允许控制器覆盖播放器,而无需额外的容器嵌套(如需了解详情,请参阅使用网格的界面元素叠加层)。

enum class VideoPlayerArea { Player, Controller }

object PlayerGridConfig {
    // Default: Single area layout with overlay (controls on top of player)
    val defaultConfig: GridConfigurationScope.() -> Unit = {
        row(1f)
        column(1f)
        area(areaId = VideoPlayerArea.Player, row = 1, column = 1)
        area(areaId = VideoPlayerArea.Controller, row = 1, column = 1)
    }

    // Tabletop: Two rows splitting content across the fold
    val tabletopConfig: GridConfigurationScope.() -> Unit = {
        row(0.5f)
        row(0.5f)
        column(1f)
        area(areaId = VideoPlayerArea.Player, row = 1, column = 1) // Top half above fold
        area(areaId = VideoPlayerArea.Controller, row = 2, column = 1) // Bottom half below fold
    }
}

2. 检测桌上姿势并将配置应用于 Grid

使用 mediaQuery 根据 windowPosture 选择有效配置,将 config 传递给 Grid,并将可组合的内容绑定到区域 ID。在 VideoPlayerArea.Controller 之前声明 VideoPlayerArea.Player 可确保当两者在 defaultConfig 中共享一个单元格时,控件会渲染在播放器上方:

val config = mediaQuery {
    when (windowPosture) {
        Posture.Tabletop -> PlayerGridConfig.tabletopConfig
        else -> PlayerGridConfig.defaultConfig
    }
}

Grid(config = config) {
    Box(
        modifier = Modifier
            .gridItem(areaId = VideoPlayerArea.Player)
    ) {
        // VideoPlayerContent
    }

    Box(
        modifier = Modifier
            .gridItem(areaId = VideoPlayerArea.Controller)
    ) {
        // PlaybackControlsContent
    }
}

结果

通过结合使用 mediaQuery 和 Grid,您的应用可以动态检测可折叠设备何时部分折叠成桌面姿势,并自动将界面调整为由折叠边分隔的两个功能性显示区域。

其他资源