Согласуйте интерфейс со строкой состояния системы

До Wear OS 7 (API 37) платформа не показывала системную строку состояния поверх окон приложений. Приложения занимали весь экран и могли отображать любой контент в верхней части (на 12 часов), например часы TimeText, собственные изогнутые заголовки или элементы управления.

Начиная с Wear OS 8 (и уже сейчас в предварительной версии Wear OS 7.1 Beta Preview Emulator, API 37.2-beta1) система показывает строку состояния поверх окон приложений в положении "12 часов". В ней отображаются время и индикаторы состояния. Чтобы избежать наложения на системную строку состояния, приложения не должны показывать собственные часы (TimeText) и должны учитывать верхние отступы окна строки состояния (автоматически обрабатываются AppScaffold и ScreenScaffold в Wear Compose 1.8 и более поздних версиях) или скрывать системную строку состояния, когда требуется полноэкранный режим.

Строка состояния в Wear OS 8
Рисунок 1. Строка состояния в Wear OS 8.

Вот основные преимущества таких кампаний:

  • Визуальное единообразие. Единый шрифт, расположение и подложка часов в системе и всех приложениях.
  • Индикаторы состояния системы. Позволяет платформе показывать значки состояния (например, индикаторы активного микрофона и местоположения, статус подключения или информацию о батарее) и время на разных поверхностях. Одновременно показывается только один значок в зависимости от приоритета.
  • Автоматическая прокрутка и координация переходов. При использовании Jetpack Compose для Wear OS 1.8 системная строка состояния автоматически скрывается, когда пользователи прокручивают контент, и снова появляется после короткой (2 секунды) задержки.

Как настроить приложение

Чтобы начать работу, выполните следующие действия:

  1. Установите Android Studio Preview (Canary).
  2. В SDK Manager скачайте образ системы эмулятора Wear OS 7.1 Preview (API 37.2-beta1). В этой версии вы можете получить ранний доступ к строке состояния Wear OS 8, не дожидаясь выхода Wear OS 8 SDK.
  3. В Диспетчере устройств создайте и запустите виртуальное устройство Wear OS, используя образ API 37.2-beta1.

Чтобы добавить поддержку системной строки состояния, обновите версию targetSdk приложения до 35 или выше. Платформа активирует системную строку состояния только для приложений, предназначенных для API 35 и более поздних версий, чтобы сохранить обратную совместимость с устаревшими приложениями. Кроме того, обновите зависимости Wear Compose до последней альфа-версии (сейчас это 1.8.0-alpha02), как показано в следующем фрагменте кода. Если в вашем приложении используется более старая версия Wear Compose, вы можете использовать навык миграции Wear Compose Material 3, чтобы упростить миграцию.

android {
    defaultConfig {
        targetSdk = 35
    }
}

dependencies {
    implementation("androidx.wear.compose:compose-foundation:1.8.0-alpha02")
    implementation("androidx.wear.compose:compose-material3:1.8.0-alpha02")
}

Использовать системную строку состояния

В последней альфа-версии Wear Compose Material 3 1.8.0 (сейчас это 1.8.0-alpha02) библиотека автоматически включает функцию, добавляя свойство com.google.wear.ENABLE_GLOBAL_STATUS_BAR <meta-data> в файл AndroidManifest.xml. Во время выполнения AppScaffold и ScreenScaffold проверяют, включена ли на устройстве системная строка состояния и задано ли для свойства манифеста значение true:

  • В эмуляторе предварительной версии и Wear OS 8 и более поздних версий (если включено): AppScaffold подавляет внутренний TimeText, чтобы строка состояния системы отображалась в положении "12 часов" без дублирования. ScreenScaffold пересчитывает contentPadding, чтобы учесть границы вставки строки состояния, и координирует скрытие и отображение строки состояния при прокрутке списка.
  • На устройствах с Wear OS 7 и более ранними версиями (или если пользователь не дал согласие) AppScaffold автоматически возвращается к стандартному TimeText в приложении, обеспечивая полную обратную совместимость из единой базы кода.
@Composable
fun GsbSampleApp() {
    // AppScaffold coordinates the system status bar across the app
    // and falls back to rendering TimeText on Wear OS 7 and earlier.
    AppScaffold {
        val columnState = rememberTransformingLazyColumnState()

        // ScreenScaffold includes status bar top inset clearance in
        // contentPadding and hides/shows the status bar during list scrolling.
        ScreenScaffold(scrollState = columnState) { contentPadding ->
            TransformingLazyColumn(
                state = columnState,
                contentPadding = contentPadding,
            ) {
                item {
                    ListHeader { Text("Hello Status Bar") }
                }
                items(count = 15) { index ->
                    Button(onClick = { /* Handle click */ }) {
                        Text("Item #${index + 1}")
                    }
                }
            }
        }
    }
}

Вот что произойдет при запуске примера:

  • В покое (вверху списка). Строка состояния системы отображается в положении 12 часов. Заголовок Hello Status Bar находится под областью строки состояния, не перекрывая ее и не обрезаясь.
  • Прокрутка вниз. При прокрутке списка строка состояния скрывается, а элементы списка прокручиваются от края до края за верхней рамкой.
  • Бездействие. Если вы прекратите прокрутку и отпустите экран, строка состояния автоматически появится снова примерно через две секунды.

Как работать с распространенными сценариями и настройками

В следующих разделах описывается, как обрабатывать распространенные сценарии, с которыми вы можете столкнуться при работе с системной строкой состояния.

Как обрабатывать статические экраны без прокрутки

На экранах со статическим макетом (например, Column или Box), а не прокручиваемым списком, примените contentPadding, предоставляемый ScreenScaffold, к корневому макету, чтобы верхние элементы интерфейса не перекрывали системную строку состояния:

AppScaffold {
    ScreenScaffold { contentPadding ->
        Column(modifier = Modifier.padding(contentPadding)) {
            Text("Static Screen Content")
        }
    }
}

Как работать с полноэкранными интерактивными компонентами

Полноэкранные интерактивные компоненты в Wear Compose Material 3, включая AlertDialog, Dialog, Stepper, TimePicker и DatePicker, автоматически скрывают системную строку состояния, чтобы элементы управления могли занимать всю верхнюю часть круглого экрана. Когда окно закрывается, строка состояния автоматически восстанавливается с помощью API WindowInsetsController.

Как перейти в режим погружения

Чтобы переключиться в режим погружения, в котором скрыты и строка состояния системы, и локальная TimeText, добавьте в приложение или на экран composable-функцию StatusBarSuppression. Режим погружения следует использовать только для экранов, которые пользователь видит в течение короткого времени (например, оверлеи подтверждения, диалоговые окна), или для экранов, которые занимают весь дисплей (например, полноэкранные индикаторы выполнения).

Когда использовать режим погружения на уровне экрана

Если в полноэкранном режиме должен открываться только определенный экран приложения, вызовите StatusBarSuppression() в контенте ScreenScaffold. ScreenScaffold автоматически скрывает строку состояния системы (и убирает верхний отступ для нее), пока экран активен, а затем восстанавливает ее при переходе на другие экраны.

AppScaffold {
    ScreenScaffold() {
        StatusBarSuppression()
        // Full-screen immersive content
    }
}

Когда использовать режим погружения на уровне приложения

Если все экраны приложения (или Activity) должны быть полноэкранными, используйте StatusBarSuppression на уровне AppScaffold и оберните контент, чтобы скрыть строку состояния системы на всех экранах:

// Use StatusBarSuppression at AppScaffold level and wrap your content
// to suppress status bar in the entire scaffold.
AppScaffold {
    StatusBarSuppression {
        SwipeDismissableNavHost(...) {
            // Nested screens inherit suppression and 0.dp padding
        }
    }
}

Как настроить текст для заставки

Если вам нужно показать собственный изогнутый заголовок или временно отключить системную строку состояния на определенном экране или во всем приложении во время перехода на Wear OS 8, передайте собственную composable-функцию timeText, чтобы скрыть системную строку состояния:

// Screen-level custom TimeText override:
ScreenScaffold(
    timeText = { TimeText { timeTextCurvedText("Custom Status") } },
) {
    // Content
}

// App-level opt-out using in-app TimeText:
AppScaffold(
    timeText = { TimeText() },
) {
    // Screens
}

Реализация с помощью представлений (не рекомендуется)

Если в вашем приложении используются представления Android, а не Jetpack Compose для Wear OS, включите функцию с помощью AndroidManifest.xml. В отличие от последней альфа-версии Wear Compose Material 3, в которой системная строка состояния включается автоматически, в приложениях на основе View ее нужно включить вручную, добавив тег ENABLE_GLOBAL_STATUS_BAR <meta-data> в <application>:

<application ...>
    <meta-data
        android:name="com.google.wear.ENABLE_GLOBAL_STATUS_BAR"
        android:value="true" />
</application>

Отслеживать вставки верхнего окна

Используйте ViewCompat.setOnApplyWindowInsetsListener и проверьте значение windowInsets.getInsets(WindowInsetsCompat.Type.statusBars()). Если statusBarInsets.top > 0, удалите устаревший интерфейс, который показывается в верхней части экрана, и настройте верхнее поле. В противном случае вернитесь к устаревшему интерфейсу.

ViewCompat.setOnApplyWindowInsetsListener(rootView) { view, windowInsets ->
    val statusBarInsets = windowInsets.getInsets(
        WindowInsetsCompat.Type.statusBars()
    )

    if (statusBarInsets.top > 0) {
        // status bar is visible: remove legacy 12 o'clock UI and apply top inset padding
        view.updatePadding(top = statusBarInsets.top)
    } else {
        // status bar is not visible: fall back to legacy UI and padding
    }

    WindowInsetsCompat.CONSUMED
}

Как программно скрыть и показать строку состояния

В отличие от ScreenScaffold в Compose, в приложениях на основе View необходимо явно скрывать или показывать строку состояния (например, при переходе в полноэкранный режим или при прокрутке), используя WindowInsetsControllerCompat:

val insetsController = WindowCompat.getInsetsController(window, window.decorView)

// Hide the status bar
insetsController.hide(WindowInsetsCompat.Type.statusBars())

// Show the status bar
insetsController.show(WindowInsetsCompat.Type.statusBars())

Тестирование приложения

При тестировании приложения в эмуляторе предварительной бета-версии Wear OS 7.1 (API 37.2-beta1) проверьте следующее:

  • Часы показываются только один раз. Убедитесь, что в позиции "12 часов" отображается только время из строки состояния системы и его не перекрывают устаревшие элементы TimeText в приложении и контент приложения.
  • Верхнее поле. Убедитесь, что названия экранов, заголовки и верхние кнопки отображаются под строкой состояния.
  • Полноэкранные оверлеи и диалоговые окна. Убедитесь, что диалоговые окна, средства выбора, пошаговые руководства и настраиваемые полноэкранные действия скрывают строку состояния при открытии и восстанавливают ее при закрытии.