Coordenar a IU com a barra de status do sistema

Até o Wear OS 7 (API 37), a plataforma não renderizava uma barra de status do sistema sobre as janelas do aplicativo. Os apps eram proprietários de toda a tela e podiam mostrar qualquer conteúdo na posição superior (12 horas), como um relógio TimeText no app, cabeçalhos curvos personalizados ou controles superiores.

A partir do Wear OS 8, e já disponível para testes de pré-lançamento no emulador de pré-lançamento Beta do Wear OS 7.1 (API 37.2-beta1), o sistema renderiza uma barra de status sobre as janelas do aplicativo na posição de 12 horas para mostrar os indicadores de hora e status. Para evitar sobreposição com a barra de status do sistema, os apps precisam parar de renderizar o próprio relógio (TimeText) e respeitar as inserções da janela da barra de status superior (processadas automaticamente por AppScaffold e ScreenScaffold do Wear Compose 1.8 em diante) ou ocultar a barra de status do sistema quando uma experiência imersiva em tela cheia for necessária.

Barra de status do sistema no Wear OS 8
Figura 1. Barra de status do sistema no Wear OS 8.

Os principais benefícios incluem:

  • Consistência visual: tipografia, posicionamento e placa traseira uniformes do relógio em todo o sistema e em todos os apps.
  • Indicadores de status do sistema: permite que a plataforma mostre ícones de status (como indicadores de microfone e localização ativos, status de conectividade ou informações da bateria) e o horário em todas as plataformas. Apenas um ícone é mostrado por vez, com base na prioridade.
  • Coordenação automática de rolagem e transição: quando pareada com o Jetpack Compose para Wear OS 1.8, a barra de status do sistema é ocultada automaticamente quando os usuários rolam o conteúdo e reaparece após um curto atraso de inatividade (2 segundos).

Configurar o app

Para começar, siga estas etapas de pré-requisito:

  1. Instale a pré-lançamento do Android Studio (Canary).
  2. No SDK Manager, baixe a imagem do sistema do emulador de pré-lançamento do Wear OS 7.1 (API 37.2-beta1). Essa versão oferece acesso antecipado à barra de status do sistema do Wear OS 8 antes do SDK do Wear OS 8.
  3. No Gerenciador de dispositivos, crie e inicie um dispositivo virtual do Wear OS usando a imagem da API 37.2-beta1.

Para oferecer suporte à barra de status do sistema no seu app, atualize a versão targetSdk para 35 ou mais recente. A plataforma só ativa a barra de status do sistema para apps destinados à API 35 ou mais recente para preservar a compatibilidade com versões anteriores de apps legados. Além disso, atualize suas dependências do Wear Compose para a versão Alfa mais recente, atualmente 1.8.0-alpha02, conforme mostrado no snippet de código abaixo. Se o app estiver usando uma versão mais antiga do Wear Compose, use a habilidade de migração do Wear Compose Material 3 para facilitar o processo.

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")
}

Usar a barra de status do sistema

Na versão Alfa mais recente do Wear Compose Material 3 1.8.0, atualmente 1.8.0-alpha02, a biblioteca ativa o app automaticamente mesclando a propriedade com.google.wear.ENABLE_GLOBAL_STATUS_BAR <meta-data> ao AndroidManifest.xml. No momento da execução, AppScaffold e ScreenScaffold verificam se a barra de status do sistema está ativada no dispositivo e se essa propriedade de ativação do manifesto está definida como true:

  • No emulador de pré-lançamento / Wear OS 8+ (quando ativado): o AppScaffold suprime o TimeText interno para que a barra de status do sistema seja renderizada de forma limpa na posição de 12 horas sem duplicação. ScreenScaffold recalcula contentPadding para considerar os limites de inserção da barra de status e coordena a ocultação e a exibição da barra de status conforme a lista é rolada.
  • No Wear OS 7 e em dispositivos mais antigos (ou quando não há ativação): o AppScaffold volta automaticamente a renderizar o TimeText padrão no app, mantendo total compatibilidade com versões anteriores em uma única base de código.
@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}")
                    }
                }
            }
        }
    }
}

Veja o que esperar ao executar o exemplo:

  • Em repouso (parte de cima da lista): a barra de status do sistema é mostrada na posição de 12 horas. O cabeçalho "Hello Status Bar" fica abaixo da área de inserção da barra de status, sem cortes ou sobreposições.
  • Rolagem para baixo: ao rolar os itens da lista, a barra de status é ocultada, e os itens da lista são rolados de ponta a ponta atrás da moldura superior.
  • Inativo: quando você para de rolar e solta a tela, a barra de status reaparece automaticamente após cerca de 2 segundos.

Processar cenários e personalizações comuns

As seções a seguir descrevem como lidar com cenários comuns que você pode encontrar ao trabalhar com a barra de status do sistema.

Processar telas estáticas (sem rolagem)

Em telas que usam um layout estático (como Column ou Box) em vez de uma lista de rolagem, aplique o contentPadding fornecido por ScreenScaffold ao layout raiz para que os elementos da interface na parte de cima não se sobreponham à barra de status do sistema:

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

Trabalhar com componentes interativos em tela cheia

Os componentes interativos em tela cheia no Wear Compose Material 3, incluindo AlertDialog, Dialog, Stepper, TimePicker e DatePicker, ocultam automaticamente a barra de status do sistema enquanto estão na tela para que os controles tenham acesso total à parte de cima da tela circular. Quando dispensada, a barra de status do sistema é restaurada automaticamente usando a API do controlador de encartes de janela.

Mudar para o modo imersivo

Para mudar para o modo imersivo, em que a barra de status do sistema e o TimeText local ficam ocultos, adicione o elemento combinável StatusBarSuppression ao app ou à tela. Reserve o modo imersivo para telas que o usuário vê brevemente (sobreposições de confirmação, caixas de diálogo) ou que usam toda a tela (indicadores de progresso em tela cheia).

Considere quando usar o modo imersivo no nível da tela

Se apenas uma tela específica do app precisar ser imersiva ou em tela cheia, chame StatusBarSuppression() no conteúdo do ScreenScaffold. O ScreenScaffold suprime automaticamente a barra de status do sistema (e omite o padding de inserção da barra de status superior) enquanto essa tela está ativa e, em seguida, restaura a barra de status do sistema ao voltar para outras telas:

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

Considere quando usar o modo imersivo no nível do app

Se todo o aplicativo (ou Activity) for uma experiência imersiva em tela cheia em todas as telas, use StatusBarSuppression no nível AppScaffold e envolva o conteúdo para suprimir a barra de status do sistema em todas as telas:

// 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
        }
    }
}

Mostrar substituições de texto de horário personalizado

Se você precisar mostrar um cabeçalho curvo personalizado ou desativar temporariamente a barra de status do sistema em uma tela específica ou em todo o app durante a migração para o Wear OS 8, transmitir um elemento combinável timeText personalizado vai suprimir a barra de status do sistema:

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

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

Implementar usando visualizações (não recomendado)

Se o app usa visualizações do Android em vez do Jetpack Compose para Wear OS, ative usando AndroidManifest.xml. Ao contrário da versão Alfa mais recente do Wear Compose Material 3, que ativa a barra de status do sistema automaticamente, os apps baseados em visualização precisam ativar explicitamente adicionando a tag ENABLE_GLOBAL_STATUS_BAR <meta-data> dentro de <application>:

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

Monitorar encartes de janela superiores

Use ViewCompat.setOnApplyWindowInsetsListener e verifique o valor de windowInsets.getInsets(WindowInsetsCompat.Type.statusBars()). Quando statusBarInsets.top > 0, remova a interface legada de 12 horas e ajuste o padding superior. Caso contrário, use a interface legada:

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
}

Ocultar e mostrar a barra de status de forma programática

Ao contrário do ScreenScaffold no Compose, os apps baseados em visualização precisam ocultar ou mostrar explicitamente a barra de status do sistema (por exemplo, ao entrar em uma visualização imersiva em tela cheia ou coordenar o comportamento de rolagem) usando 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())

Testar o app

Ao testar o app no emulador de pré-lançamento Beta do Wear OS 7.1 (API 37.2-beta1), verifique o seguinte:

  • O relógio aparece apenas uma vez: verifique se apenas o horário da barra de status do sistema aparece na posição de 12 horas e se nenhum TimeText legado no app e conteúdo do app se sobrepõe a ele.
  • Padding superior: verifique se os títulos, cabeçalhos e botões superiores da tela aparecem abaixo da barra de status.
  • Sobreposições e caixas de diálogo em tela cheia: verifique se as caixas de diálogo, os seletores, os steppers e as atividades personalizadas em tela cheia ocultam a barra de status quando abertos e se a restauram quando fechados.