Убедитесь, что ваш пользовательский интерфейс работает с оконными вставками

После того, как ваша активность взяла на себя управление обработкой всех вставок, вы можете использовать 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. Кроме того, все ваши макеты, использующие эти вставки, также автоматически анимируются при изменении значений вставки.

Существует два основных способа использования этих типов вставок для настройки компонуемых макетов: модификаторы заполнения и модификаторы размера вставки.

Модификаторы заполнения

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 ) автоматически используют часть вставок, которые применяются в качестве заполнения. При более глубоком изучении дерева композиции вложенные модификаторы заполнения вставки и модификаторы размера вставки знают, что некоторая часть вставок уже занята внешними модификаторами заполнения вставки, и избегают использования одной и той же части вставок более одного раза, что приведет к слишком большому дополнительному пространству.

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

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

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

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

Когда IME закрыт, модификатор imePadding() не применяет заполнения, поскольку 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 . Это полезно для информирования детей, когда заполнение или интервал обеспечивается каким-либо другим механизмом, отличным от модификаторов заполнения вставки, например обычным 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 .

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