Платформа Android отвечает за отображение системного пользовательского интерфейса, такого как строка состояния и панель навигации. Этот системный пользовательский интерфейс отображается независимо от того, какое приложение использует пользователь.
WindowInsets
предоставляет информацию о системном пользовательском интерфейсе, чтобы гарантировать, что ваше приложение рисует в правильной области и ваш пользовательский интерфейс не заслоняется системным пользовательским интерфейсом.
![Переход от края к краю, чтобы рисовать за системными панелями](https://developer.android.com/static/develop/ui/compose/images/layouts/insets/e2e-intro.gif?authuser=9&hl=ru)
В Android 14 (уровень API 34) и более ранних версиях пользовательский интерфейс вашего приложения по умолчанию не отображается под системными панелями и не отображает вырезы.
На Android 15 (уровень API 35) и более поздних версиях ваше приложение отображается под системными панелями и вырезами дисплея, как только ваше приложение нацелено на SDK 35. Это обеспечивает более удобный пользовательский интерфейс и позволяет вашему приложению в полной мере использовать пространство окна, доступное для это.
Отображение контента за системным пользовательским интерфейсом называется «от края до края» . На этой странице вы узнаете о различных типах вставок, о том, как работать от края до края и как использовать API-интерфейсы вставок для анимации вашего пользовательского интерфейса и обеспечения того, чтобы содержимое вашего приложения не было закрыто элементами системного пользовательского интерфейса.
Основы вставки
Когда приложение работает от края до края, вам необходимо убедиться, что важный контент и взаимодействия не скрыты системным пользовательским интерфейсом. Например, если кнопка расположена за панелью навигации, пользователь не сможет ее нажать.
Размер системного пользовательского интерфейса и информация о том, где он расположен, задаются с помощью вставок .
Каждая часть системного пользовательского интерфейса имеет соответствующий тип вставки, описывающий ее размер и место ее размещения. Например, вставки строки состояния определяют размер и положение строки состояния, тогда как вставки панели навигации определяют размер и положение панели навигации. Каждый тип вставки состоит из четырех измерений в пикселях: сверху, слева, справа и снизу. Эти размеры определяют, насколько далеко пользовательский интерфейс системы простирается от соответствующих сторон окна приложения. Поэтому, чтобы избежать дублирования с этим типом системного пользовательского интерфейса, пользовательский интерфейс приложения должен быть вставлен на эту величину.
Эти встроенные типы вставок Android доступны через WindowInsets
:
Вставки, описывающие строки состояния. Это верхние панели пользовательского интерфейса системы, содержащие значки уведомлений и другие индикаторы. | |
Строка состояния вставляется, когда она видна. Если строки состояния в настоящее время скрыты (из-за входа в полноэкранный режим), то вставки основной строки состояния будут пустыми, но эти вставки будут непустыми. | |
Вставки, описывающие панели навигации. Это панели системного пользовательского интерфейса слева, справа или снизу устройства, описывающие панель задач или значки навигации. Они могут меняться во время выполнения в зависимости от предпочтительного метода навигации пользователя и взаимодействия с панелью задач. | |
Панель навигации вставляется, когда она видна. Если панели навигации в настоящее время скрыты (из-за входа в полноэкранный режим), то вставки основной панели навигации будут пустыми, но эти вставки будут непустыми. | |
Вставка, описывающая оформление окна пользовательского интерфейса системы, если оно находится в окне произвольной формы, например, верхняя строка заголовка. | |
Строка заголовка вставляется, когда она видна. Если панели заголовка в настоящее время скрыты, то основные вставки панели заголовка будут пустыми, но эти вставки будут непустыми. | |
Объединение вставок системной панели, включающих строки состояния, панели навигации и строку заголовка. | |
Системная панель вставляется, когда она видна. Если системные панели в настоящее время скрыты (из-за входа в полноэкранный режим), то вставки основной системной панели будут пустыми, но эти вставки будут непустыми. | |
Вставки, описывающие количество места внизу, которое занимает программная клавиатура. | |
Вставки, описывающие объем места, которое занимала программная клавиатура до текущей анимации клавиатуры. | |
Вставки, описывающие объем места, которое займет программная клавиатура после текущей анимации клавиатуры. | |
Тип вставок, описывающих более подробную информацию о пользовательском интерфейсе навигации и указывающих объем пространства, в котором «нажатия» будут обрабатываться системой, а не приложением. Для прозрачных панелей навигации с навигацией с помощью жестов некоторые элементы приложения можно нажимать через пользовательский интерфейс системной навигации. | |
Вставки сенсорных элементов, когда они видимы. Если нажимаемые элементы в настоящее время скрыты (из-за входа в полноэкранный режим погружения), то вставки основных нажимаемых элементов будут пустыми, но эти вставки будут непустыми. | |
Вставки представляют количество вставок, в которых система будет перехватывать жесты для навигации. Приложения могут вручную указать обработку ограниченного количества этих жестов с помощью | |
Подмножество системных жестов, которые всегда будут обрабатываться системой и от которых нельзя отказаться с помощью | |
Вставки обозначают расстояние, необходимое для того, чтобы избежать перекрытия выреза дисплея (выемки или точечного отверстия). | |
Вставки представляют изогнутые области изображения водопада. Дисплей-водопад имеет изогнутые области по краям экрана, где экран начинает загибаться по бокам устройства. |
Эти типы суммируются тремя «безопасными» типами вставок, которые гарантируют, что содержимое не будет скрыто:
Эти «безопасные» типы вставок защищают контент по-разному в зависимости от вставок базовой платформы:
- Используйте
WindowInsets.safeDrawing
для защиты содержимого, которое не должно отображаться под каким-либо системным пользовательским интерфейсом. Это наиболее распространенное использование вставок: для предотвращения рисования содержимого, скрытого пользовательским интерфейсом системы (частично или полностью). - Используйте
WindowInsets.safeGestures
для защиты содержимого с помощью жестов. Это позволяет избежать конфликта системных жестов с жестами приложений (например, для нижних листов, каруселей или в играх). - Используйте
WindowInsets.safeContent
как комбинациюWindowInsets.safeDrawing
иWindowInsets.safeGestures
чтобы обеспечить отсутствие визуального перекрытия содержимого и перекрытия жестов.
Настройка вставок
Чтобы предоставить вашему приложению полный контроль над тем, где оно отображает контент, выполните следующие действия по настройке. Без этих действий ваше приложение может отображать черный или сплошной цвет за системным пользовательским интерфейсом или не синхронизировать анимацию с программной клавиатурой.
- Используйте SDK 35 или более поздней версии, чтобы обеспечить сквозную работу на Android 15 и более поздних версиях. Ваше приложение отображается за системным пользовательским интерфейсом. Вы можете настроить пользовательский интерфейс своего приложения, обрабатывая вставки.
- При необходимости вызовите
enableEdgeToEdge()
вActivity.onCreate()
, что позволит вашему приложению работать без ограничений в предыдущих версиях Android. Установите
android:windowSoftInputMode="adjustResize"
в записиAndroidManifest.xml
вашего действия. Этот параметр позволяет вашему приложению получать размер программного 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
После того, как ваша активность взяла на себя управление обработкой всех вставок, вы можете использовать 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)
. Аналогичные модификаторы имеются и для других типов вставок.
Модификаторы размера вставки
Следующие модификаторы применяют количество вставок окон, устанавливая размер компонента равным размеру вставок:
Применяет начальную сторону windowInsets в качестве ширины (например, | |
Применяет конечную сторону windowInsets в качестве ширины (например, | |
Применяет верхнюю часть windowInsets в качестве высоты (например, | |
| Применяет нижнюю часть windowInsets в качестве высоты (например, |
Эти модификаторы особенно полезны для изменения размера 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.
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
или разделителями фиксированной высоты:
@OptIn(ExperimentalLayoutApi::class) 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 .
Значение вставок обновляется после этапа композиции, но до этапа макета. Это означает, что при чтении значения вставок в композиции обычно используется значение вставок, опоздавшее на один кадр. Встроенные модификаторы, описанные на этой странице, созданы для задержки использования значений вставок до этапа макета, что гарантирует, что значения вставок будут использоваться в том же кадре, в котором они обновляются.
Анимация клавиатуры IME с помощью WindowInsets
Вы можете применить Modifier.imeNestedScroll()
к контейнеру прокрутки, чтобы автоматически открывать и закрывать IME при прокрутке до нижней части контейнера.
class WindowInsetsExampleActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) WindowCompat.setDecorFitsSystemWindows(window, false) setContent { MaterialTheme { MyScreen() } } } } @OptIn(ExperimentalLayoutApi::class) @Composable fun MyScreen() { Box { LazyColumn( modifier = Modifier .fillMaxSize() // fill the entire window .imePadding() // padding for the bottom for the IME .imeNestedScroll(), // scroll IME at the bottom content = { } ) FloatingActionButton( modifier = Modifier .align(Alignment.BottomEnd) .padding(16.dp) // normal 16dp of padding for FABs .navigationBarsPadding() // padding for navigation bar .imePadding(), // padding for when IME appears onClick = { } ) { Icon(imageVector = Icons.Filled.Add, contentDescription = "Add") } } }
![Анимация, показывающая, как элемент пользовательского интерфейса прокручивается вверх и вниз, освобождая место для клавиатуры.](https://developer.android.com/static/develop/ui/compose/images/interop-keyboard.gif?authuser=9&hl=ru)
Поддержка вставки для компонентов материала 3
Для простоты использования многие встроенные составные элементы Material 3 ( androidx.compose.material3
) сами обрабатывают вставки в зависимости от того, как составные элементы размещаются в вашем приложении в соответствии со спецификациями материала.
Обработка вставок составных элементов
Ниже приведен список компонентов материала , которые автоматически обрабатывают вставки.
Панели приложений
-
TopAppBar
/SmallTopAppBar
/CenterAlignedTopAppBar
/MediumTopAppBar
/LargeTopAppBar
: применяет верхнюю и горизонтальную стороны системных панелей в качестве заполнения, поскольку они используются в верхней части окна. -
BottomAppBar
: применяет нижнюю и горизонтальную стороны системных полос в качестве заполнения.
Контейнеры контента
-
ModalDrawerSheet
/DismissibleDrawerSheet
/PermanentDrawerSheet
(содержимое внутри модального навигационного ящика): применяет вертикальные и начальные вставки к содержимому. -
ModalBottomSheet
: применяет нижние вставки. -
NavigationBar
: применяет нижнюю и горизонтальную вставки. -
NavigationRail
: применяет вертикальные и начальные вставки.
Строительные леса
По умолчанию Scaffold
предоставляет вставки в качестве paddingValues
параметров, которые вы можете использовать. Scaffold
не применяет вставки к содержимому; эта ответственность лежит на вас. Например, чтобы использовать эти вставки с помощью LazyColumn
внутри Scaffold
:
Scaffold { innerPadding -> // innerPadding contains inset information for you to use and apply LazyColumn( // consume insets as scaffold doesn't do it by default modifier = Modifier.consumeWindowInsets(innerPadding), contentPadding = innerPadding ) { items(count = 100) { Box( Modifier .fillMaxWidth() .height(50.dp) .background(colors[it % colors.size]) ) } } }
Переопределить вставки по умолчанию
Вы можете изменить параметр windowInsets
, передаваемый составному объекту, чтобы настроить его поведение. Этот параметр может представлять собой вставку окна другого типа, которую следует применить вместо этого, или отключить его, передав пустой экземпляр: WindowInsets(0, 0, 0, 0)
.
Например, чтобы отключить обработку вставок в LargeTopAppBar
, установите для параметра windowInsets
пустой экземпляр:
LargeTopAppBar( windowInsets = WindowInsets(0, 0, 0, 0), title = { Text("Hi") } )
Взаимодействие со вставками системы View
Возможно, вам придется переопределить вставки по умолчанию, если на вашем экране код Views и Compose находится в одной и той же иерархии. В этом случае вам необходимо четко указать, какие вставки следует использовать, а какие следует игнорировать.
Например, если ваш самый внешний макет представляет собой макет Android View, вам следует использовать вставки в системе View и игнорировать их для Compose. В качестве альтернативы, если ваш внешний макет является составным, вам следует использовать вставки в Compose и соответствующим образом дополнять составные элементы AndroidView
.
По умолчанию каждый ComposeView
использует все вставки на уровне использования WindowInsetsCompat
. Чтобы изменить это поведение по умолчанию, установите для ComposeView.consumeWindowInsets
значение false
.
Ресурсы
- Теперь и в Android — полнофункциональное приложение для Android, полностью созданное с помощью Kotlin и Jetpack Compose.
- Управление сквозным контролем в Android 15 – кодовая лаборатория, посвященная сквозному контролю в Android 15.
- 3 вещи, которые улучшат работу вашего приложения для Android: Edge to Edge, Predictive Back и Glance — видео на YouTube, рассказывающее о сквозном обеспечении Android 15
- От края до края и вставки | Советы по созданию — видео на YouTube, показывающее, как использовать вставки для рисования от края до края.
Рекомендуется для вас
- Примечание. Текст ссылки отображается, когда JavaScript отключен.
- Материальные компоненты и макеты
- Перенос
CoordinatorLayout
в Compose - Другие соображения