Mostrar conteúdo de ponta a ponta no app

Testar o Compose
O Jetpack Compose é o kit de ferramentas de interface recomendado para Android. Aprenda a trabalhar com o modo de ponta a ponta no Compose.

Depois de direcionar o SDK 35 ou mais recente em um dispositivo com o Android 15 ou mais recente, o app será mostrado de ponta a ponta. A janela abrange toda a largura e altura da tela, sendo renderizada atrás das barras do sistema. As barras do sistema incluem a barra de status, de legenda e de navegação.

Muitos apps têm uma barra de apps na parte de cima. A barra de apps superior precisa se estender até a borda superior da tela e aparecer atrás da barra de status. Opcionalmente, a barra de apps de cima pode ser reduzida para a altura da barra de status quando o conteúdo rola.

Muitos apps também têm uma barra de apps ou de navegação na parte de baixo. Essas barras também precisam se estender até a borda inferior da tela e aparecer atrás da barra de navegação. Caso contrário, os apps vão mostrar o conteúdo de rolagem por trás da barra de navegação.

Figura 1. Barras do sistema em um layout de ponta a ponta.

Ao implementar um layout de borda a borda no seu app, lembre-se do seguinte:

  1. Ativar uma tela de ponta a ponta
  2. Processe todas as sobreposições visuais.
  3. Considere mostrar telas de sombreamento atrás das barras do sistema.
Exemplo de imagem por trás da barra de status
Figura 2. Exemplo de imagem por trás da barra de status.

Ativar a exibição de ponta a ponta

Se o app for destinado ao SDK 35 ou mais recente, o modo de tela cheia será ativado automaticamente para dispositivos com o Android 15 ou mais recente.

Para ativar a tela cheia em versões anteriores do Android, faça o seguinte:

  1. Adicione uma dependência à biblioteca androidx.activity no arquivo build.gradle do app ou módulo:

    Kotlin

    dependencies {
        val activity_version = activity_version
        // Java language implementation
        implementation("androidx.activity:activity:$activity_version")
        // Kotlin
        implementation("androidx.activity:activity-ktx:$activity_version")
    }

    Groovy

    dependencies {
        def activity_version = activity_version
        // Java language implementation
        implementation 'androidx.activity:activity:$activity_version'
        // Kotlin
        implementation 'androidx.activity:activity-ktx:$activity_version'
    }
  2. Importe a função de extensão enableEdgeToEdge para o app:

Ative manualmente a exibição de ponta a ponta chamando enableEdgeToEdge no onCreate do Activity. Ele precisa ser chamado antes de setContentView.

Kotlin

     override fun onCreate(savedInstanceState: Bundle?) {
       enableEdgeToEdge()
       super.onCreate(savedInstanceState)
       ...
     }
   

Java

     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
       EdgeToEdge.enable(this);
       super.onCreate(savedInstanceState);
       ...
     }
   

Por padrão, o enableEdgeToEdge() deixa as barras do sistema transparentes, exceto no modo de navegação com três botões, em que a barra de status recebe uma tela translúcida. As cores dos ícones do sistema e do filtro são ajustadas com base no tema claro ou escuro do sistema.

A função enableEdgeToEdge() declara automaticamente que o app precisa ser distribuído de borda a borda e ajusta as cores das barras do sistema.

Para ativar a tela de ponta a ponta no app sem usar a função enableEdgeToEdge(), consulte Configurar manualmente a tela de ponta a ponta.

Processar sobreposições usando insets

Algumas das visualizações do app podem ser renderizadas atrás das barras do sistema, conforme mostrado na Figura 3.

É possível resolver sobreposições reagindo a insets, que especificam quais partes da tela se cruzam com a interface do sistema, como a barra de navegação ou a barra de status. A interseção pode significar exibição acima do conteúdo, mas também pode informar o app sobre gestos do sistema.

Os tipos de insetos que se aplicam à exibição do app de borda a borda são:

  • Encartes de barras do sistema:melhores para visualizações que podem ser tocadas e que não podem ser ocultadas visualmente pelas barras do sistema.

  • Mostrar recortes:para áreas em que pode haver um corte na tela devido à forma do dispositivo.

  • Insets de gestos do sistema:para áreas de navegação por gestos usadas pelo sistema que têm prioridade sobre o app.

Inserções de barras do sistema

Os insets de barra do sistema são o tipo mais usado. Eles representam a área em que a IU do sistema aparece no eixo Z acima do app. Eles são mais usados para mover ou preencher visualizações no app que podem ser tocadas e que não podem ser visualmente ocultas pelas barras do sistema.

Por exemplo, o botão de ação flutuante (FAB) na Figura 3 está parcialmente obscurecido pela barra de navegação:

Exemplo de implementação de borda a borda, mas a barra de navegação está cobrindo o FAB
Figura 3. Barra de navegação que se sobrepõe a um FAB em um layout de borda a borda.

Para evitar esse tipo de sobreposição visual no modo de gestos ou de botão, é possível aumentar as margens da visualização usando getInsets(int) com WindowInsetsCompat.Type.systemBars().

O exemplo de código a seguir mostra como implementar inserções de barra do sistema:

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(fab) { v, windowInsets ->
  val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
  // Apply the insets as a margin to the view. This solution sets
  // only the bottom, left, and right dimensions, but you can apply whichever
  // insets are appropriate to your layout. You can also update the view padding
  // if that's more appropriate.
  v.updateLayoutParams<MarginLayoutParams> {
      leftMargin = insets.left
      bottomMargin = insets.bottom
      rightMargin = insets.right
  }

  // Return CONSUMED if you don't want want the window insets to keep passing
  // down to descendant views.
  WindowInsetsCompat.CONSUMED
}

Java

ViewCompat.setOnApplyWindowInsetsListener(fab, (v, windowInsets) -> {
  Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
  // Apply the insets as a margin to the view. This solution sets only the
  // bottom, left, and right dimensions, but you can apply whichever insets are
  // appropriate to your layout. You can also update the view padding if that's
  // more appropriate.
  MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
  mlp.leftMargin = insets.left;
  mlp.bottomMargin = insets.bottom;
  mlp.rightMargin = insets.right;
  v.setLayoutParams(mlp);

  // Return CONSUMED if you don't want want the window insets to keep passing
  // down to descendant views.
    return WindowInsetsCompat.CONSUMED;
});

Se você aplicar essa solução ao exemplo mostrado na Figura 3, não haverá sobreposição visual no modo de botão, como mostrado na Figura 4:

uma barra de navegação translúcida que não cobre o FAB
Figura 4. Solução de sobreposição visual no modo button.

O mesmo se aplica ao modo de navegação por gestos, conforme mostrado na Figura 5:

de ponta a ponta com navegação por gestos
Figura 5. Solução de sobreposição visual no modo de navegação por gestos.

Mostrar cortes de tela

Alguns dispositivos têm recortes na tela. Normalmente, o recorte fica na parte de cima da tela e incluído na barra de status. Quando a tela do dispositivo está no modo paisagem, o recorte pode estar na borda vertical. Dependendo do conteúdo que seu app mostra na tela, implemente o padding para evitar cortes na tela, já que, por padrão, os apps são renderizados no corte da tela.

Por exemplo, muitas telas de apps mostram uma lista de itens. Não obscureça os itens da lista com o recorte da tela ou as barras do sistema.

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(binding.recyclerView) { v, insets ->
  val bars = insets.getInsets(
    WindowInsetsCompat.Type.systemBars()
      or WindowInsetsCompat.Type.displayCutout()
  )
  v.updatePadding(
    left = bars.left,
    top = bars.top,
    right = bars.right,
    bottom = bars.bottom,
  )
  WindowInsetsCompat.CONSUMED
}

Java

ViewCompat.setOnApplyWindowInsetsListener(mBinding.recyclerView, (v, insets) -> {
  Insets bars = insets.getInsets(
    WindowInsetsCompat.Type.systemBars()
    | WindowInsetsCompat.Type.displayCutout()
  );
  v.setPadding(bars.left, bars.top, bars.right, bars.bottom);
  return WindowInsetsCompat.CONSUMED;
});

Determine o valor de WindowInsetsCompat usando a lógica ou das barras do sistema e os tipos de recorte de exibição.

Defina clipToPadding como RecyclerView para que o padding role com os itens da lista. Isso permite que os itens fiquem atrás das barras do sistema quando o usuário rola a tela, conforme mostrado no exemplo abaixo.

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

Inserções de gestos do sistema

Os engastes de gestos do sistema representam as áreas da janela em que os gestos do sistema têm prioridade sobre o app. Essas áreas são mostradas em laranja na Figura 6:

Exemplo de engastes de gestos do sistema
Figura 6. Inserções de gestos do sistema.

Assim como os engastes da barra do sistema, você pode evitar a sobreposição dos engastes de gestos do sistema usando getInsets(int) com WindowInsetsCompat.Type.systemGestures().

Use esses encartes para mover ou preencher as visualizações deslizáveis longe das bordas. Os casos de uso comuns incluem folhas de resumo, deslização em jogos e carrosséis implementados usando ViewPager2.

No Android 10 ou versões mais recentes, os recuos de gestos do sistema contêm um recuo inferior para o gesto de início e um recuo à esquerda e à direita para os gestos de volta:

Exemplo de medições de inserção de gestos do sistema
Figura 7. Medidas de inserção de gestos do sistema.

O exemplo de código a seguir mostra como implementar inserções de gestos do sistema:

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets ->
    val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures())
    // Apply the insets as padding to the view. Here, set all the dimensions
    // as appropriate to your layout. You can also update the view's margin if
    // more appropriate.
    view.updatePadding(insets.left, insets.top, insets.right, insets.bottom)

    // Return CONSUMED if you don't want the window insets to keep passing down
    // to descendant views.
    WindowInsetsCompat.CONSUMED
}

Java

ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
    Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures());
    // Apply the insets as padding to the view. Here, set all the dimensions
    // as appropriate to your layout. You can also update the view's margin if
    // more appropriate.
    view.setPadding(insets.left, insets.top, insets.right, insets.bottom);

    // Return CONSUMED if you don't want the window insets to keep passing down
    // to descendant views.
    return WindowInsetsCompat.CONSUMED;
});

Componentes do Material

Muitos componentes do Material Design para Android (com.google.android.material){:.external} baseados em visualizações processam encartes automaticamente, incluindo BottomAppBar, BottomNavigationView, NavigationRailView e NavigationView.

No entanto, AppBarLayout não processa automaticamente os insetos. Adicione android:fitsSystemWindows="true" para processar os insetos superiores.

Leia como processar insets com componentes do Material Design no Compose.

Envio de insetos compatível com versões anteriores

Para interromper o envio de insets para visualizações filhas e evitar o excesso de padding, consuma insets usando a constante WindowInsetsCompat.CONSUMED. No entanto, em dispositivos com o Android 10 (nível 29 da API e versões anteriores), os insets não são enviados para irmãos depois de chamar WindowInsetsCompat.CONSUMED, o que pode causar sobreposições visuais indesejadas.

Exemplo de envio de inseto corrompido
Figura 8. Exemplo de envio de inseto corrompido. As insets não são enviadas para visualizações irmãs depois que o ViewGroup 1 consome insets no Android 10 (nível 29 da API) e versões anteriores, fazendo com que o TextView 2 se sobreponha à barra de navegação do sistema. No entanto, os insets são enviados para visualizações irmãs no Android 11 (nível 30 da API) e versões mais recentes, como esperado.

Para confirmar que os insets são enviados para irmãos em todas as versões do Android com suporte, use ViewGroupCompat#installCompatInsetsDispatch antes de consumir insets, disponível no AndroidX Core e Core-ktx 1.16.0-alpha01 e versões mais recentes.

Kotlin

// Use the i.d. assigned to your layout's root view, e.g. R.id.main
val rootView = findViewById(R.id.main)
// Call before consuming insets
ViewGroupCompat.installCompatInsetsDispatch(rootView)

Java

// Use the i.d. assigned to your layout's root view, e.g. R.id.main
LinearLayout rootView = findViewById(R.id.main);
// Call before consuming insets
ViewGroupCompat.installCompatInsetsDispatch(rootView);
Exemplo de envio de insetos corrigido
Figura 9. Correção do envio de insets após a chamada de ViewGroupCompat#installCompatInsetsDispatch.

Modo imersivo

Alguns conteúdos ficam melhores em tela cheia, oferecendo ao usuário uma experiência mais imersiva. É possível ocultar as barras do sistema para o modo imersivo usando as bibliotecas WindowInsetsController e WindowInsetsControllerCompat:

Kotlin

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

// Hide the system bars.
windowInsetsController.hide(Type.systemBars())

// Show the system bars.
windowInsetsController.show(Type.systemBars())

Java

Window window = getWindow();
WindowInsetsControllerCompat windowInsetsController =
      WindowCompat.getInsetsController(window, window.getDecorView());
if (windowInsetsController == null) {
    return;
  }
// Hide the system bars.
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars());

// Show the system bars.
windowInsetsController.show(WindowInsetsCompat.Type.systemBars());

Consulte Ocultar as barras de sistema para o modo imersivo para mais informações sobre a implementação desse recurso.

Ícones da barra do sistema

A chamada de enableEdgeToEdge garante que as cores do ícone da barra do sistema sejam atualizadas quando o tema do dispositivo mudar.

Ao usar o modo de uma borda à outra, talvez seja necessário atualizar manualmente as cores do ícone da barra do sistema para que elas contrastem com o plano de fundo do app. Por exemplo, para criar ícones de barra de status claros:

Kotlin

WindowCompat.getInsetsController(window, window.decorView)
    .isAppearanceLightStatusBars = false

Java

WindowCompat.getInsetsController(window, window.getDecorView())
    .setAppearanceLightStatusBars(false);

Proteção da barra de sistema

Quando o app é direcionado ao SDK 35 ou mais recente, o preenchimento de tela é aplicado. A barra de status do sistema e as barras de navegação por gestos são transparentes, mas a barra de navegação com três botões é translúcida.

Para remover a proteção em segundo plano padrão da navegação com três botões, defina Window.setNavigationBarContrastEnforced como false.

Outros recursos

Consulte as referências a seguir para mais informações sobre WindowInsets, navegação por gestos e como os insets funcionam: