Макет настольной версии игры с использованием сетки и медиазапросов.

значок 4-звездочного рейтинга

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

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

Передовые методы

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

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

Ингредиенты

  • Grid : Адаптивный контейнер компоновки, позволяющий размещать элементы в настраиваемых строках и столбцах, идеально подходящий для разделения контента на отдельные области экрана.
  • mediaQuery : API Jetpack Compose, используемый для запроса текущего положения окна приложения, классов размеров и характеристик оборудования непосредственно в ваших компонуемых объектах.

Шаги

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

1. Определите конфигурации сетки для настольного режима.

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

В defaultConfig обе области назначаются одной и той же ячейке ( row = 1, column = 1 ). Grid использует неявную z-индексацию, при которой элементы, объявленные позже в макете, отображаются поверх более ранних, что позволяет контроллеру накладываться на плеер без дополнительной вложенности контейнеров (подробнее см. раздел «Наложение элементов пользовательского интерфейса с помощью 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 и привяжите компонуемый контент к идентификаторам областей. Объявление 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 , ваше приложение динамически определяет, когда складное устройство частично сложено в положение для размещения на столе, и автоматически преобразует свой пользовательский интерфейс в две функциональные области отображения, разделенные зоной сгиба.

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