WindowInsets — это стандартный API в Jetpack Compose для управления областями экрана, которые частично или полностью скрыты системным интерфейсом. К таким областям относятся строка состояния, панель навигации и экранная клавиатура. В качестве альтернативы вы можете передавать предопределенные WindowInsetsRulers такие как SafeDrawing , в Modifier.fitInside или Modifier.fitOutside , чтобы выровнять содержимое по системным панелям и вырезу на экране, или создавать собственные WindowInsetsRulers .
Преимущества линеек WindowInsetsRulers
- Избегает сложностей, связанных с потреблением ресурсов : работает на этапе размещения элементов компоновки. Это означает, что полностью обходит цепочку потребления отступов и всегда может обеспечить правильное, абсолютное позиционирование системных панелей и вырезов для отображения, независимо от того, что сделали родительские элементы компоновки. Использование методов
Modifier.fitInsideилиModifier.fitOutsideпомогает исправить проблемы, когда родительские элементы компоновки некорректно потребляют отступы. - Легко избегайте системных панелей : это помогает содержимому вашего приложения избегать системных панелей и выреза на экране, и может быть проще, чем использовать
WindowInsetsнапрямую. - Высокая степень настраиваемости : разработчики могут выравнивать контент по пользовательским линейкам и точно контролировать макеты с помощью настраиваемых макетов.
Недостатки WindowInsetsRulers
- Не подходит для измерений : поскольку работает на этапе размещения, предоставляемая им информация о положении недоступна на более раннем этапе измерения.
Выравнивайте контент с помощью методов-модификаторов.
Modifier.fitInside позволяет приложениям выравнивать контент по системным панелям и отображать вырезы. Его можно использовать вместо WindowInsets . Modifier.fitOutside обычно является обратной функцией к Modifier.fitInside .
Например, чтобы убедиться, что содержимое приложения не заходит на системные полосы и вырез в экране, можно использовать fitInside(WindowInsetsRulers.safeDrawing.current) .
@Composable fun FitInsideDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() // Or DisplayCutout, Ime, NavigationBars, StatusBar, etc... .fitInside(WindowInsetsRulers.SafeDrawing.current) ) }
В следующей таблице показано, как будет выглядеть содержимое вашего приложения с предопределенными линейками, имеющими параметры Modifier.fitInside или Modifier.fitOutside .
| Предопределенный тип линейки | ||
|---|---|---|
![]() | ![]() | |
![]() | Н/Д | |
![]() | ![]() | |
![]() | Н/Д (вместо этого используйте | |
![]() | ![]() |
Использование Modifier.fitInside и Modifier.fitOutside требует, чтобы компонуемые объекты были ограничены. Это означает, что необходимо определить модификаторы, такие как Modifier.size или Modifier.fillMaxSize .
Некоторые линейки, такие как Modifier.fitOutside в SafeDrawing и SystemBars возвращают несколько линеек. В этом случае Android размещает Composable, используя одну линейку слева, сверху, справа и снизу.
Избегайте использования IME с помощью Modifier.fitInside
Для обработки нижних элементов с помощью IME с Modifier.fitInside передайте объект RectRuler , который принимает значение самого внутреннего элемента NavigationBar и Ime .
@Composable fun FitInsideWithImeDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() .fitInside( RectRulers.innermostOf( WindowInsetsRulers.NavigationBars.current, WindowInsetsRulers.Ime.current ) ) ) { TextField( value = "Demo IME Insets", onValueChange = {}, modifier = modifier.align(Alignment.BottomStart).fillMaxWidth() ) } }
Избегайте строки состояния и строки заголовка с помощью Modifier.fitInside
Аналогично, чтобы убедиться, что верхние элементы избегают строки состояния и строки заголовка, а также Modifier.fitInsider , передайте RectRuler , который принимает самое внутреннее значение из StatusBars и CaptionBar .
@Composable fun FitInsideWithStatusAndCaptionBarDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() .fitInside( RectRulers.innermostOf( WindowInsetsRulers.StatusBars.current, WindowInsetsRulers.CaptionBar.current ) ) ) }
Создайте пользовательские WindowInsetsRulers
Вы можете выравнивать контент по пользовательским линейкам. Например, рассмотрим случай, когда родительский компонент некорректно обрабатывает отступы, вызывая проблемы с отступами в дочернем компоненте. Хотя эту проблему можно решить и другими способами, в том числе с помощью Modifier.fitInside , вы также можете создать пользовательскую линейку для точного выравнивания дочернего компонента без необходимости исправлять проблему в родительском компоненте, как показано в следующем примере и видео:
@Composable fun WindowInsetsRulersDemo(modifier: Modifier) { Box( contentAlignment = BottomCenter, modifier = modifier .fillMaxSize() // The mistake that causes issues downstream, as .padding doesn't consume insets. // While it's correct to instead use .windowInsetsPadding(WindowInsets.navigationBars), // assume it's difficult to identify this issue to see how WindowInsetsRulers can help. .padding(WindowInsets.navigationBars.asPaddingValues()) ) { TextField( value = "Demo IME Insets", onValueChange = {}, modifier = modifier // Use alignToSafeDrawing() instead of .imePadding() to precisely place this child // Composable without having to fix the parent upstream. .alignToSafeDrawing() // .imePadding() // .fillMaxWidth() ) } } fun Modifier.alignToSafeDrawing(): Modifier { return layout { measurable, constraints -> if (constraints.hasBoundedWidth && constraints.hasBoundedHeight) { val placeable = measurable.measure(constraints) val width = placeable.width val height = placeable.height layout(width, height) { val bottom = WindowInsetsRulers.SafeDrawing.current.bottom .current(0f).roundToInt() - height val right = WindowInsetsRulers.SafeDrawing.current.right .current(0f).roundToInt() val left = WindowInsetsRulers.SafeDrawing.current.left .current(0f).roundToInt() measurable.measure(Constraints.fixed(right - left, height)) .place(left, bottom) } } else { val placeable = measurable.measure(constraints) layout(placeable.width, placeable.height) { placeable.place(0, 0) } } } }
В следующем видео показан пример проблемного использования отступов IME, вызванного родительским элементом на изображении слева, и использование пользовательских линеек для решения проблемы справа. Под элементом TextField Composable отображается дополнительный отступ, поскольку отступы панели навигации не были учтены родительским элементом. Дочерний элемент размещен в правильном месте на изображении справа с помощью пользовательской линейки, как показано в предыдущем примере кода.
Убедитесь, что родители ограничены.
Для безопасного использования WindowInsetsRulers убедитесь, что родительский элемент предоставляет допустимые ограничения. Родительские элементы должны иметь заданный размер и не могут зависеть от размера дочернего элемента, использующего WindowInsetsRulers . Используйте fillMaxSize или другие модификаторы размера для родительских элементов Composable.
Аналогично, размещение компонуемого объекта, использующего WindowInsetsRulers внутри прокручиваемого контейнера, такого как verticalScroll может привести к неожиданному поведению, поскольку прокручиваемый контейнер предоставляет неограниченные ограничения по высоте, которые несовместимы с логикой линейки.







