Советы по обработке Insets для обеспечения edge-to-edge на Android 15

Перевод статьи от Android Developers.

Согласно внутреннему исследованию Google, пользователи предпочитают экраны edge-to-edge, а не edge-to-edge, как для навигации жестами, так и для навигации тремя кнопками.

Рисунок 1. Сверху или слева: приложение edge-to-edge. Фон приложения прорисовывается под строкой состояния сверху и строкой навигации снизу. Снизу или справа: приложение, которое не поддерживает edge-to-edge. Фон и содержимое приложения не попадают в строку состояния и навигационную панель.

Android 15 обеспечивает переход на edge-to-edge

До target SDK 35 (Android 15) ваше приложение не будет отрисовываться от края до края без явных изменений в коде для намеренного перехода на edge-to-edge. После установки targetSdk=35 или выше система будет рисовать ваше приложение от края до края по умолчанию на устройствах Android 15 и более поздних версий. Хотя это изменение может облегчить многим приложениям переход на edge-to-edge, критически важные элементы пользовательского интерфейса могут оказаться недоступными для пользователей. Ваше приложение должно работать с Insets, чтобы критически важные элементы пользовательского интерфейса оставались доступными.

Рисунок 2. Приложение, использующее SDK 34 на устройстве Android 15. Приложение не поддерживает edge-to-edge.

Рисунок 3. Приложение, использующее SDK 35 на устройстве Android 15. Приложение расположено от края до края, но Insets не обрабатываются. Строка состояния, навигационная строка и вырез дисплея заслоняют пользовательский интерфейс.

Рисунок 4. Приложение, использующее SDK 35 на устройстве Android 15. Приложение расположено от края до края, а Insets обрабатываются таким образом, чтобы не заслонять важные элементы пользовательского интерфейса.

Если ваше приложение уже использует edge-to-edge или immersive mode, это эти изменения не коснутся его. Тем не менее, стоит проверить свое приложение на наличие проблем с UI.

Советы по обработке Insets

Существуют различные API и атрибуты, которые можно использовать для работы с Insets, чтобы избежать перекрытия системным интерфейсом или вырезом дисплея.

В этой статье описаны следующие советы, применимые к Compose и Views:

  1. Используйте Material Components, чтобы упростить обработку Insets
  2. Рисуйте фон от края до края, а критически важные элементы UI обрабатывайте с помощью Insets
  3. Обрабатывайте вырезы дисплея и панель заголовка
  4. Не забывайте про последний элемент списка
  5. Не забывайте про IME
  6. Для обратной совместимости используйте enableEdgeToEdge вместо setDecorFitsSystemWindows
  7. Сохраняйте цвет системных панелей только при необходимости

Также статья содержит советы, касающиеся только Compose:

  1. Используйте PaddingValues из Scaffold
  2. Используйте высокоуровневый API WindowInset

И наконец, статья содержит советы, касающиеся только Views:

  1. Используйте ViewCompat.setOnApplyWindowInsetsListener вместо fitsSystemWindows=true
  2. Применяйте Insets, основываясь на высоте тулбара в разметке

1. Используйте Material Components, чтобы упростить обработку Insets

Многие элементы Material Components автоматически обрабатывают Insets, к примеру фон компонента рисуется внутри области системной строки, а к критически важному UI добавляется отступ (см. совет № 2). Некоторые из этих компонентов не обрабатывают Insets автоматически, но предоставляют методы, облегчающие работу с ними.

Компоненты Material 3 (androidx.compose.material3), которые автоматически обрабатывают вставки:

  • BottomAppBar
  • CenterAlignedTopAppBar
  • DismissibleDrawerSheet
  • LargeTopAppBar
  • MediumTopAppBar
  • ModalBottomSheet
  • ModalDrawerSheet
  • NavigationBar
  • NavigationRail
  • NavigationSuiteScaffold
  • PermanentDrawerSheet
  • TopAppBar
  • SmallTopAppBar

Компоненты Material 2 (androidx.compose.material) по умолчанию не обрабатывают Insets самостоятельно, в отличие от компонентов Material 3.  Поэтому рассмотрите возможность обновления до Material 3. С другой стороны, многие компоненты Material 2 поддерживают указание Insets с помощью параметра windowInsets, такие как BottomAppBar, TopAppBar, BottomNavigation и NavigationRail. Аналогичным образом используйте параметр contentWindowInsets для Scaffold. В противном случае применяйте Insets в качестве отступов.

Material View Components (com.google.android.material), которые автоматически обрабатывают Insets:

  • BottomAppBar
  • BottomNavigationView
  • NavigationRailView
  • NavigationView

2. Рисуйте фон от края до края, а критически важные элементы UI обрабатывайте с помощью Insets

Часто приложения устанавливают системным панелям тот же цвет, что и у панелей приложения, чтобы они отображались «от края до края», но это является неправильным решением.

Рисунок 5. Приложение, использующее SDK 34 на устройстве Android 15. В приложении установлены цвета панели состояния и навигационной панели, которые больше не поддерживаются после перехода на SDK 35. Цвет панелей состояния и навигации намеренно задан немного разным, чтобы вы могли отличить системные панели от панелей приложения, но обычно приложения используют одинаковые цвета для системных панелей и панелей приложения, чтобы они выглядели от края до края.

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

Чтобы улучшить пользовательский интерфейс этого приложения после применения edge-to-edge, нужно расширить фон панелей приложения, чтобы они рисовались под прозрачными системными панелями, а затем установить отступы для текста и кнопок так, чтобы они не попадали на системные панели. Компоненты Material 3 TopAppBars и BottomAppBars делают это автоматически. Для компонентов Material 2 используйте параметр windowInsets. Для Views некоторые компоненты Material обрабатывают это автоматически. В противном случае следует использовать fitsSystemWindows или ViewCompat.setOnApplyWindowInsetsListener.

Рисунок 6. Использование edge-to-edge. Слева: Insets не обрабатываются. Справа: Insets обрабатываются. Панели приложения рисуются под прозрачными системными панелями, а текст и иконки расположены с учётом отступа от системных панелей.

3. Обрабатывайте вырезы дисплея и панель заголовка

При работе с Insets учитывайте вырезы дисплея и панель заголовка, а также панели состояния и навигации.

Вырезы в дисплее

В вырезе дисплея часто находится камера. После перехода на SDK 35 ваше приложение может иметь важный UI под вырезом дисплея, особенно если вырез расположен по левому или правому краю устройства.

Например, до перехода на SDK 35 ваше приложение могло иметь большую белую рамку, чтобы учесть вырез камеры в альбомной ориентации.

Рисунок 7. Приложение, использующее SDK 34 на устройстве Android 15.

После перехода на SDK 35 белая рамка исчезает, а все содержимое смещается влево. Некоторое содержимое прорисовывается под вырезом камеры.

Рисунок 8. Приложение, использующее SDK 35 на устройстве Android 15. Камера перекрывает фотографию Овечки.

Работа с вырезами дисплея в Compose

В Compose можно легко обрабатывать вырезы на экране с помощью WindowInsets.safeContent, WindowInsets.safeDrawing или WindowInsets.safeGestures. Или можно использовать WindowInsets.displayCutout для более точного контроля. К сожалению, на момент написания этой статьи PaddingValues в Scaffold еще не учитывает вырезы дисплея.

// Демонстрация с использованием WindowInsets.displayCutout для точного управления.
// Но часто бывает достаточно и проще воспользоваться
// WindowInsets.safeContent, WindowInsets.safeDrawing или WindowInsets.safeGestures.
@Composable
fun ChatRow(...) {
   val layoutDirection = LocalLayoutDirection.current
   val displayCutout = WindowInsets.displayCutout.asPaddingValues()
   val startPadding = displayCutout.calculateStartPadding(layoutDirection)
   val endPadding = displayCutout.calculateEndPadding(layoutDirection)
   Row(
       modifier = modifier.padding(
               PaddingValues(
                   top = 16.dp,
                   bottom = 16.dp,
                   // При повороте устройства убедитесь, 
                   // что вырезы на дисплее не закрывают содержимое.
                   start = startPadding.coerceAtLeast(16.dp),
                   end = endPadding.coerceAtLeast(16.dp)
               )
           ),
       ...
   ) { ... }

После обработки вырезов дисплея приложение выглядит следующим образом:

Рисунок 9. Приложение, использующее SDK 35 на устройстве Android 15. Insets с вырезами дисплея обработаны. Примечание: в идеале «Чаты» также должны быть иметь отступ справа.

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

Подробнее об этом примере можно узнать в codelab, Handle edge-to-edge enforcements in Android 15.

Обработка вырезов дисплея в Views

В Views можно обрабатывать вырезы на экране с помощью WindowInsetsCompat.Type.displayCutout. Пример кода см. в документации.

Примечание: Если в вашем приложении есть неплавающее окно (например, Activity), использующее LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT, LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER или LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES, Android будет интерпретировать эти режимы вырезания как LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS, начиная с Android 15, что приведет к перерисовке окна в области выреза дисплея. Обязательно протестируйте экраны, использующие DEFAULT, NEVER или SHORT_EDGES.

Панель заголовка

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

Рисунок 10. Панель заголовка в эмуляторе рабочего стола.

При работе Insets в Compose используйте либо PaddingValues из Scaffold, либо WindowInsets.safeContent, WindowInsets.safeDrawing, или WindowInsets.systemBars, которые включают в себя панель заголовка. Не используйте WindowInsets.statusBars.

В случае с Views, используйте WindowInsetsCompat.Type.systemBars. Не используйте WindowInsetsCompat.Type.statusBars.

4. Не забывайте про последний элемент списка

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

Обработка последнего элемента списка в Compose

Чтобы обработать последний элемент списка в Compose, используйте contentPadding у LazyColumn, чтобы добавить пробел к последнему элементу, если вы не используете TextField:

Scaffold { innerPadding ->
    LazyColumn(
        contentPadding = innerPadding
    ) {
        // Контент, не содержащий TextField
    }
}

Для TextField используйте Spacer, чтобы нарисовать последний TextField в LazyColumn. Подробный обзор работы с Insets в списках приведен в разделе Применение Insets.

LazyColumn(
    Modifier.imePadding()
) {
    // Контент, содержащий TextField
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

Обработка последнего элемента списка в Views

Добавление clipToPadding=»false» может обеспечить отображение последнего элемента списка над панелью навигации для RecyclerView или NestedScrollView. Возьмем, к примеру, следующее приложение. После установки SDK 35 пользовательский интерфейс списка приложения отображает последний элемент списка под панелью навигации.

Рисунок 11. Приложение с RecyclerView. Сверху: используется SDK 34. Последний элемент списка отображается над трехкнопочной навигацией. Снизу: используется SDK 35. Последний элемент списка отрисовывается под трехкнопочной навигацией.

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

Рисунок 12. Приложение работает с insets, но ощущается менее иммерсивным, поскольку контент не прокручивается за системными панелями.

// Рисунок 12
ViewCompat.setOnApplyWindowInsetsListener(
    findViewById(R.id.recycler_view)
) { v, insets ->
    val innerPadding = insets.getInsets(
        // Обратите внимание, мы используем systemBars, а не statusBar.
        WindowInsetsCompat.Type.systemBars()
        // Обратите внимание, что мы также учитываем вырезы на дисплее.
        or WindowInsetsCompat.Type.displayCutout()
        // При использовании EditText также добавьте 
        // «or WindowInsetsCompat.Type.ime()» для
        // сохранения фокуса при открытии IME.
    )
    v.setPadding(
        innerPadding.left,
        innerPadding.top,
        innerPadding.right,
        innerPadding.bottom)
    insets
}

Однако теперь приложение выглядит менее иммерсивным. Чтобы добиться желаемого результата, добавьте clipToPadding=false, чтобы последний элемент списка располагался над строкой навигации и список был виден при прокрутке за строкой навигации (и строкой состояния).

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

<!-- Рисунок 13 -->
<RecyclerView
  ...
  android:clipToPadding="false" />

5. Не забывайте про IME

Установите android:windowSoftInputMode=»adjustResize» в AndroidManifest.xml у вашей Activity, чтобы выделить место для IME (или программной клавиатуры) на экране.

Работа с IME Insets в Compose

Учитывайте IME с помощью Modifier.imePadding(). Например, это может помочь сохранить фокус на текстовом поле в LazyColumn, когда открывается IME. Пример кода и пояснения см. в разделе Применение Insets.

Работа с IME Insets в Views

До перехода на SDK 35 использование android:windowSoftInputMode=»adjustResize» — это все, что требовалось для сохранения фокуса, например, на EditText в RecyclerView при открытии IME. При использовании «adjustResize» фреймворк рассматривал IME как системное окно, а корневые представления окна подставлялись так, чтобы содержимое не накладывалось на системное окно.

После перехода на SDK 35 вы также должны учитывать IME с помощью ViewCompat.setOnApplyWindowInsetsListener и WindowInsetsCompat.Type.ime(), поскольку фреймворк не будет добавлять отступ к корневым вьюхам окна. Смотрите пример кода для Рисунка 12.

6. Для обратной совместимости используйте enableEdgeToEdge вместо setDecorFitsSystemWindows

После того как ваше приложение обработает insets, сделайте так, чтобы в предыдущих версиях Android оно также поддерживало edge-to-edge. Для этого используйте метод enableEdgeToEdge вместо setDecorFitsSystemWindows. Метод enableEdgeToEdge содержит в себе около 100 строк кода, которые необходимы для полноценной обратной совместимости.

7. Сохраняйте цвет системных панелей только при необходимости

Во большинстве случаев, сохраняйте новые настройки Android 15 по умолчанию. Панель состояния и панель навигации жестов должны быть прозрачными, а трехкнопочная навигация — полупрозрачной после перехода на SDK 35 (см. Рисунок 1).

Однако бывают случаи, когда необходимо сохранить цвет фона системных панелей, но API для установки цвета панелей состояния и навигации теперь помечены как deprecated. Мы планируем выпустить библиотеку поддержки AndroidX для этого варианта использования. Тем временем, если ваше приложение должно показывать свой фоновый цвет для 3-кнопочной навигации или панели состояния, вы можете разместить composable или view элемент за системной панелью, используя WindowInsets.Type#tappableElement() для получения высоты 3-кнопочной навигационной панели или WindowInsets.Type#statusBars.

Например, чтобы показать цвет элемента за 3-кнопочной навигацией в Compose, установите для свойства window.isNavigationBarContrastEnforced значение false. Установка этого свойства в false делает 3-кнопочную навигацию полностью прозрачной (примечание: это свойство не влияет на навигацию жестами).

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

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            window.isNavigationBarContrastEnforced = false
            MyTheme {
                Surface(...) {
                    MyContent(...)
                    ProtectNavigationBar()
                }
            }
        }
    }
}


// Используйте только при необходимости.
@Composable
fun ProtectNavigationBar(modifier: Modifier = Modifier) {
   val density = LocalDensity.current
   val tappableElement = WindowInsets.tappableElement
   val bottomPixels = tappableElement.getBottom(density)
   val usingTappableBars = remember(bottomPixels) {
       bottomPixels != 0
   }
   val barHeight = remember(bottomPixels) {
       tappableElement.asPaddingValues(density).calculateBottomPadding()
   }

   Column(
       modifier = modifier.fillMaxSize(),
       verticalArrangement = Arrangement.Bottom
   ) {
       if (usingTappableBars) {
           Box(
               modifier = Modifier
                   .background(MaterialTheme.colorScheme.background)
                   .fillMaxWidth()
                   .height(barHeight)
           )
       }
   }
}

Советы по работе с Insets для UI, использующего Compose

Следующие советы применимы только к приложениям, использующим Jetpack Compose. Дополнительные советы, связанные с Compose, смотрите в этом видео: Edge-to-edge and insets | Compose Tips.

8. Используйте PaddingValues из Scaffold

Для Compose используйте Scaffold вместо Surface, чтобы организовать пользовательский интерфейс приложения с помощью TopAppBar, BottomAppBar, NavigationBar и NavigationRail. Используйте параметр PaddingValues в Scaffold для обработки Insets в критических элементах UI. В большинстве случаев это все, что вам нужно сделать.

Однако бывают случаи, когда применение PaddingValues в Scaffold приводит к неожиданным результатам. Scaffold’s PaddingValues включает в себя вставки для верхнего, нижнего, левого и правого краев экрана. Вам могут понадобиться значения только для некоторых краев. Один из подходов — сделать копию параметра и вручную настроить верхние, нижние, левые и правые insets так, чтобы не применять слишком большой отступ.

Рисунок 14. Слева: Поле ввода внизу заслонено навигационной панелью после перехода на SDK 35. Посередине: Значения PaddingValues от Scaffold, примененные к полю ввода. Система использует размер панели состояния и тулбара приложения для расчета значения верхнего отступа, который создает лишнее пространство над полем ввода. Справа: Применены значения PaddingValues для Scaffold, но верхний отступ удален вручную.

Вот неправильный код, создающий лишний отступ, который можно видеть посередине на Рисунке 14.

// Вызывает лишний отступ, как показано посередине на Рисунке 14.
Scaffold { innerPadding -> // innerPadding is Scaffold's PaddingValues
    InputBar(
        ...
        contentPadding = innerPadding
     ) {...}
}

Вот исправленный код, который генерирует правильный отступ, как показано справа на Рисунке 14.

// Функция для создания копии PaddingValues ​​с использованием существующих
// значений по умолчанию, если не указано другое значение.
​​private fun PaddingValues.copy(
    layoutDirection: LayoutDirection,
    start: Dp? = null,
    top: Dp? = null,
    end: Dp? = null,
    bottom: Dp? = null,
) = PaddingValues(
    start = start ?: calculateStartPadding(layoutDirection),
    top = top ?: calculateTopPadding(),
    end = end ?: calculateEndPadding(layoutDirection),
    bottom = bottom ?: calculateBottomPadding(),
)

// Обеспечивает правильный отступ, как показано справа на Рисунке 14.
Scaffold { innerPadding -> // innerPadding is Scaffold's PaddingValues
    val layoutDirection = LocalLayoutDirection.current
    InputBar(
        ...
        contentPadding = innerPadding.copy(layoutDirection, top = 0.dp)
    ) {...}
}

9. Используйте высокоуровневый API WindowInset

Подобно PaddingValues в Scaffold, вы также можете использовать высокоуровневые API WindowInset, чтобы легко и безопасно рисовать критически важные элементы пользовательского интерфейса. К ним относятся:

  • WindowInsets.safeDrawing
  • WindowInsets.safeGestures
  • WindowInsets.safeContent

Более подробную информацию см. в разделе «Основы Insets«.

Советы по работе с Insets для UI, использующего Views

Следующие советы применимы только к приложениям на основе Views.

10. Используйте ViewCompat.setOnApplyWindowInsetsListener вместо fitsSystemWindows=true

Вы можете использовать fitsSystemWindows=true для обработки insets в вашем приложении. Это простое изменение кода в 1 строку. Однако не используйте fitsSystemWindows во вьюхе, которая содержит весь ваш макет (включая фон). Это приведет к тому, что ваше приложение будет выглядеть не от края до края, поскольку fitsSystemWindows обрабатывает insets по всем краям.

Рисунок 15. Применение edge-to-edge. Слева: fitsSystemWindows=false (по умолчанию). Справа: fitsSystemWindows=true. Это не тот результат, который мы хотим получить, потому что приложение не выглядит от края до края.

Рисунок 16. Применение edge-to-edge, fitsSystemWindows=true. Отступ по левому краю вызван вырезом дисплея, которого здесь нет. Это не тот результат, который мы хотим получить, потому что приложение не выглядит от края до края.

Добавьте fitsSystemWindows в CoordinatorLayout и AppBarLayout, и AppBarLayout будет рисовать от края до края, что нам и нужно.

Рисунок 17. Применение edge-to-edge. Слева: AppBarLayout не обрабатывает insets автоматически. Справа: Добавление fitsSystemWindows в AppBarLayout и CoordinatorLayout, чтобы рисовать от края до края.

<!-- Рисунок 17 -->
<CoordinatorLayout
  android:fitsSystemWindows="true"
  ...>
    <AppBarLayout
      android:fitsSystemWindows="true"
    ...>
      <TextView
        android:text="App Bar Layout"
      .../>
   </AppBarLayout>
</CoordinatorLayout>

В данном случае AppBarLayout использовал fitsSystemWindows, чтобы нарисовать фон под панелью состояния, а не избегать её, что противоречило бы нашим ожиданиям. Более того, AppBarLayout с fitsSystemWindows=true применяет отступ только для верхней, но не для нижней, левой или правой границы.

Объекты CoordinatorLayout и AppBarLayout имеют следующее поведение при переопределении fitsSystemWindows:

  • CoordinatorLayout: фоны дочерних представлений рисуются под системными панелями, если для этих вьюх также установлено значение fitsSystemWindows=true. К содержимому этих вьюх (например, тексту, значкам, изображениям) автоматически применяются отступы с учётом системных панелей и вырезов дисплея.
  • AppBarLayout: рисуется под системными барами, если fitsSystemWindows=true, и автоматически применяет верхний отступ к содержимому.

В большинстве случаев для обработки insets используйте ViewCompat.setOnApplyWindowInsetsListener, поскольку он позволяет определить, какие границы должны обрабатывать insets, и имеет последовательное поведение. Примеры кода см. в советах #4 и #11.

11. Применяйте Insets, основываясь на высоте тулбара в разметке

Если вы обнаружили, что содержимое вашего приложения скрывается под панелью приложения, вам может понадобиться применить insets после того, как панель приложения будет размещена, с учетом высоты панели приложения.

Например, если под AppBarLayout во FrameLayout находится прокручивающийся контент, можно использовать код, приведённый ниже, чтобы обеспечить появление прокручивающегося контента после AppBarLayout. Обратите внимание, что отступ применяется внутри doOnLayout.

val myScrollView = findViewById(R.id.my_scroll_view)
val myAppBar = findViewById(R.id.my_app_bar_layout)


ViewCompat.setOnApplyWindowInsetsListener(myScrollView) { scrollView, windowInsets ->
   val insets = windowInsets.getInsets(
       WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()
   )
   myAppBar.doOnLayout { appBar ->
       scrollView.updatePadding(
           left = insets.left,
           right = insets.right,
           top = appBar.height,
           bottom = insets.bottom
       )
   }
   WindowInsetsCompat.CONSUMED
}

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

Нужно больше времени на миграцию?

Чтобы обеспечить надлежащую поддержку интерфейса «от края до края», может потребоваться значительная работа. Прежде чем перейти на SDK 35, подумайте, сколько времени вам потребуется на внесение необходимых изменений в приложение.

Если вам нужно больше времени для обработки insets, чтобы они были совместимы с поведением edge-to-edge по умолчанию , вы можете временно отказаться от использования этого функционала с помощью флага R.attr#windowOptOutEdgeToEdgeEnforcement. Но не планируйте использовать этот флаг бесконечно, так как в ближайшем будущем он станет нефункциональным.

Флаг может быть особенно полезен для приложений, содержащих десятки и сотни активностей. Вы можете отказаться от поддержки edge-to-edge в каждой активности по отдельности, а затем — сделать свое приложение от края до края по одной активности за раз.

Вот один из подходов к использованию этого флага. Если ваш minSDK меньше 35, этот атрибут должен быть в файле values-v35.xml.

<!-- В values-v35.xml -->
<resources>
  <!-- TODO: Удалить после того, как активности обработают insets. -->
  <style name="OptOutEdgeToEdgeEnforcement">
    <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
  </style>
</resources>

Для прошлых версий создайте пустой стиль в values.xml:

<!-- В values.xml -->
<resources>
  <!-- TODO: Удалить после того, как активности обработают insets. -->
  <style name="OptOutEdgeToEdgeEnforcement">
    <!-- android:windowOptOutEdgeToEdgeEnforcement
    не поддерживается до версии SDK 35.
    Этот пустой стиль позволяет программно отказаться от использования. -->
  </style>
</resources>

Вызовите стиль перед обращением к decor view в setContentView:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {

        // Вызов перед доступом к DecorView в setContentView
        theme.applyStyle(R.style.OptOutEdgeToEdgeEnforcement, /* force */ false)

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        ...
    }
}

Ресурсы

Сегодня состоялся релиз Android 15 AOSP. Наша команда создала блоги, видеоролики и кодовые лаборатории, чтобы помочь подготовить ваше приложение к работе с Android 15 от края до края. Ниже приведен список старых и новых ресурсов для дальнейшего обучения.

Документация

Видео

Кодовые лаборатории

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *