Как настроить вставки окон

После того как Activity начнет обрабатывать все вставки, вы сможете использовать API Compose, чтобы убедиться, что контент не скрыт и интерактивные элементы не перекрывают системный интерфейс. Эти API также синхронизируют макет приложения с изменениями отступов.

Как обрабатывать вставки с помощью модификаторов размера или полей

Например, вот самый простой способ применить отступы ко всему контенту приложения:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    enableEdgeToEdge()

    setContent {
        Box(Modifier.safeDrawingPadding()) {
            // the rest of the app
        }
    }
}

Этот фрагмент кода применяет отступы окна safeDrawing в качестве полей вокруг всего контента приложения. Это гарантирует, что интерактивные элементы не будут перекрываться системным интерфейсом, но также означает, что ни один элемент приложения не будет отрисовываться за системным интерфейсом, чтобы создать эффект полноэкранного режима. Чтобы использовать все окно, необходимо точно настроить, где будут применяться вставки, для каждого экрана или компонента.

Все эти типы отступов автоматически анимируются с помощью анимаций IME, которые были перенесены в API 21. Таким образом, все макеты, в которых используются эти отступы, также будут автоматически анимированы при изменении значений отступов.

Чтобы настроить макеты Composable, можно использовать три способа обработки отступов:

Модификаторы полей

Modifier.windowInsetsPadding(windowInsets: WindowInsets) применяет заданные вставки окна в качестве отступов, действуя так же, как Modifier.padding. Например, Modifier.windowInsetsPadding(WindowInsets.safeDrawing) применяет безопасные вставки для рисования в качестве отступов со всех четырех сторон.

Также есть несколько встроенных вспомогательных методов для наиболее распространенных типов врезок. Modifier.safeDrawingPadding() – один из таких методов, эквивалентный Modifier.windowInsetsPadding(WindowInsets.safeDrawing). Для других типов отступов существуют аналогичные модификаторы.

Модификаторы размера отступа

Следующие модификаторы применяют размер отступов окна, задавая размер компонента равным размеру отступов:

Modifier.windowInsetsStartWidth(windowInsets: WindowInsets)

Применяет левую сторону windowInsets в качестве ширины (как Modifier.width).

Modifier.windowInsetsEndWidth(windowInsets: WindowInsets)

Применяет правую сторону windowInsets в качестве ширины (как Modifier.width).

Modifier.windowInsetsTopHeight(windowInsets: WindowInsets)

Применяет верхнюю сторону windowInsets в качестве высоты (как Modifier.height).

Modifier.windowInsetsBottomHeight(windowInsets: WindowInsets)

Применяет нижнюю сторону windowInsets в качестве высоты (например, Modifier.height).

Эти модификаторы особенно полезны для определения размера Spacer, занимающего пространство, которое обычно занимают вставки:

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

Встроенный контент

Модификаторы внутренних отступов (windowInsetsPadding и вспомогательные модификаторы, такие как safeDrawingPadding) автоматически используют часть внутренних отступов, которая применяется в качестве отступов. При переходе на более глубокие уровни дерева композиции вложенные модификаторы inset padding и inset size учитывают, что часть отступов уже была использована внешними модификаторами inset padding, и не используют одну и ту же часть отступов более одного раза, чтобы не создавать слишком много дополнительного пространства.

Модификаторы размера отступов также не позволяют использовать одну и ту же часть отступов более одного раза, если отступы уже были обработаны. Однако, поскольку они напрямую изменяют свой размер, они не используют вставки.

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

В примере с LazyColumn, который мы рассматривали ранее, размер LazyColumn изменяется с помощью модификатора imePadding. Внутри элемента LazyColumn последний элемент имеет высоту, равную высоте нижней части системных панелей:

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

Когда IME закрыт, imePadding() не добавляет отступы. В результате вставки не используются, а высота Spacer соответствует высоте системных панелей внизу экрана.

Когда открывается IME, вставки IME анимируются в соответствии с размером IME, а модификатор imePadding() начинает применять нижний отступ, чтобы изменить размер LazyColumn при открытии IME. Поскольку модификатор imePadding() начинает применять нижний отступ, он также начинает использовать это количество отступов. Поэтому высота Spacer начинает уменьшаться, так как часть интервала для системных панелей уже применена модификатором imePadding(). Если модификатор imePadding() добавляет нижнее поле, размер которого превышает размер системных панелей, высота элемента Spacer будет равна нулю.

Когда IME закрывается, изменения происходят в обратном порядке: Spacer расширяется с нулевой высоты, поскольку imePadding() применяется меньше, чем нижние системные панели. Наконец, высота Spacer совпадает с высотой системных панелей после того, как IME полностью исчезнет.

Рисунок 2. Ленивый столбец от края до края с TextField.

Такое поведение достигается за счет взаимодействия всех модификаторов windowInsetsPadding и может быть изменено несколькими способами.

Modifier.consumeWindowInsets(insets: WindowInsets) также использует вставки так же, как и Modifier.windowInsetsPadding, но не применяет их в качестве отступов. Это полезно в сочетании с модификаторами размера вставки, чтобы указать соседним элементам, что определенное количество вставок уже использовано:

Column(Modifier.verticalScroll(rememberScrollState())) {
    Spacer(Modifier.windowInsetsTopHeight(WindowInsets.systemBars))

    Column(
        Modifier.consumeWindowInsets(
            WindowInsets.systemBars.only(WindowInsetsSides.Vertical)
        )
    ) {
        // content
        Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
    }

    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars))
}

Modifier.consumeWindowInsets(paddingValues: PaddingValues) работает так же, как и версия с аргументом WindowInsets, но использует произвольный PaddingValues. Это полезно, чтобы сообщать детям, когда отступы или интервалы задаются не с помощью модификаторов inset padding, а с помощью других механизмов, например обычного тега Modifier.padding или элементов с фиксированной высотой:

Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) {
    // content
    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
}

Если вам нужны необработанные вставки окна, используйте значения WindowInsets напрямую или WindowInsets.asPaddingValues(), чтобы получить PaddingValues необработанных вставок. Однако из-за указанных ниже ограничений рекомендуется по возможности использовать модификаторы отступов окна и модификаторы размера отступов окна.

Вставки и фазы Jetpack Compose

Compose использует основные API AndroidX для обновления и анимации отступов, которые, в свою очередь, используют API платформы для управления отступами. Из-за особенностей этой платформы у отступов особая связь с фазами Jetpack Compose.

Значение параметра insets обновляется после этапа композиции, но до этапа макета. Это означает, что при чтении значения отступов в композиции обычно используется значение отступов, которое на один кадр отстает от текущего. Встроенные модификаторы, описанные на этой странице, предназначены для того, чтобы отложить использование значений отступов до этапа макета. Это гарантирует, что значения отступов будут использоваться в том же кадре, в котором они были обновлены.