Макет для настольного режима с сеткой и медиазапросом

Значок оценки "4 звезды"

В настольном режиме на складных устройствах единый экран разделяется на две функциональные области, разделенные физической складкой (или шарниром). В настольном режиме основной контент приложения (например, видеопроигрыватель или игровое поле) можно разместить в верхней половине экрана, а интерактивные элементы (например, элементы управления мультимедиа или контроллеры) – в нижней.

Складное устройство в настольном режиме. На верхнем экране воспроизводится видеоконтент, а на нижнем – элементы управления воспроизведением.
Рисунок 1. В настольном режиме контент и интерактивные элементы управления разделены физическим сгибом.

Рекомендации

Чтобы добавить поддержку режима настольного устройства в приложение, используйте API Grid, чтобы определить макет с двумя строками и одним столбцом, и примените медиазапрос положения окна настольного устройства.

  • Реактивное определение режима настольного устройства. Используйте composable-функцию mediaQuery, чтобы отслеживать состояние устройства. Когда устройство складывается в настольный режим (windowPosture == Posture.Tabletop), динамически меняйте макет без перезапуска действий или сложной обработки жизненного цикла.
  • Структурируйте макеты с помощью Grid. В настольном режиме используйте API Grid (2 rows, 1 column), чтобы разделить основной визуальный контент в верхней строке в видимой части страницы и интерактивные элементы управления в нижней строке в невидимой нижней части страницы.
  • Используйте неявную z-индексацию для наложений. В стандартных положениях (не в режиме ноутбука) назначьте несколько идентификаторов областей одной ячейке, чтобы наложить элементы управления на проигрыватель. Grid автоматически отрисовывает элементы в порядке их объявления.
  • Обеспечьте плавные переходы. Убедитесь, что состояние и положение прокрутки сохраняются при переходе между стандартными полноэкранными макетами и настольным режимом.

Ингредиенты

  • Grid – контейнер адаптивного макета, который позволяет размещать элементы в настраиваемых строках и столбцах. Идеально подходит для разделения контента по разным областям экрана.
  • mediaQuery – API Jetpack Compose, который используется для запроса текущего положения окна приложения, классов размера и аппаратных характеристик непосредственно в composable-функциях.

Шаги

Запросите состояние устройства с помощью mediaQuery(). Когда устройство находится в настольном режиме, расположите контент приложения в вертикальной сетке с двумя строками и одним столбцом. Основной контент должен оставаться вверху, а элементы управления – внизу.

1. Как настроить сетку для настольного режима

Внутри composable-функции определите идентификаторы областей макета с помощью перечисления и настройте блоки GridConfigurationScope для стандартного и настольного режимов.

В defaultConfig обе области назначены одной ячейке (row = 1, column = 1). В Grid используется неявная z-индексация, при которой composable-функции, объявленные в макете позже, отображаются поверх предыдущих. Это позволяет контроллеру перекрывать проигрыватель без дополнительного вложения контейнеров (подробнее см. в разделе Наложение элементов интерфейса с помощью Grid).

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. Определять положение устройства на столе и применять конфигурацию к сетке

Используйте mediaQuery, чтобы выбрать активную конфигурацию на основе windowPosture, передайте config в Grid и привяжите composable-контент к идентификаторам областей. Если объявить VideoPlayerArea.Player перед VideoPlayerArea.Controller, то когда они оба будут находиться в одной ячейке в 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 позволяет приложению динамически определять, когда складное устройство частично сложено в настольном режиме, и автоматически разделять интерфейс на две функциональные области, разделенные сгибом.

Дополнительные ресурсы