Настройка вставок окон

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

  1. Нацельтесь на Android 15 (уровень API 35) или выше, чтобы обеспечить Edge-to-Edge на Android 15 и выше. Ваше приложение отображается за системным пользовательским интерфейсом. Вы можете настроить пользовательский интерфейс своего приложения, обрабатывая вставки.
  2. При желании можно вызвать enableEdgeToEdge() в Activity.onCreate() , что позволит вашему приложению работать от края до края на предыдущих версиях Android.
  3. Установите android:windowSoftInputMode="adjustResize" в записи AndroidManifest.xml вашего Activity. Этот параметр позволяет вашему приложению получать размер программного IME в виде вставок, что помогает вам применять соответствующую компоновку и отступы, когда IME появляется и исчезает в вашем приложении.

    <!-- In your AndroidManifest.xml file: -->
    <activity
      android:name=".ui.MainActivity"
      android:label="@string/app_name"
      android:windowSoftInputMode="adjustResize"
      android:theme="@style/Theme.MyApplication"
      android:exported="true">
    

Используйте API Compose

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

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

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

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

Также есть несколько встроенных методов-утилит для наиболее распространенных типов вставок. 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 ​​для потребления. Это полезно для информирования потомков, когда padding или spacing предоставляются каким-то другим механизмом, нежели модификаторы inset padding, например, обычным Modifier.padding или фиксированными разделителями высоты:

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

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

Вставки и фазы создания реактивного ранца

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

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