Configurar encartes de janela

Depois que a atividade assumir o controle de todas as inserções, use as APIs do Compose para verificar se o conteúdo não está oculto e se os elementos interativos não se sobrepõem à IU do sistema. Essas APIs também sincronizam o layout do app com as mudanças de encarte.

Processar encartes usando modificadores de padding ou tamanho

Por exemplo, este é o método mais básico de aplicar as inserções ao conteúdo de todo o app:

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

    enableEdgeToEdge()

    setContent {
        Box(Modifier.safeDrawingPadding()) {
            // the rest of the app
        }
    }
}

Esse snippet aplica os encartes de janela safeDrawing como padding em todo o conteúdo do app. Embora isso garanta que os elementos interativos não se sobreponham à interface do sistema, também significa que nenhuma parte do app será mostrada atrás da interface do sistema para criar um efeito de ponta a ponta. Para aproveitar ao máximo toda a janela, é necessário ajustar onde os encartes são aplicados em cada tela ou componente.

Todos esses tipos de encarte são animados automaticamente com animações de IME com suporte retroativo para a API 21. Por extensão, todos os layouts que usam esses encartes também são animados automaticamente conforme os valores de encarte mudam.

Há três maneiras de processar as inserções para ajustar os layouts combináveis:

Modificadores de padding

Modifier.windowInsetsPadding(windowInsets: WindowInsets) aplica os encartes de janela fornecidos como padding, agindo como Modifier.padding. Por exemplo, Modifier.windowInsetsPadding(WindowInsets.safeDrawing) aplica as inserções de desenho seguro como padding nos quatro lados.

Também há vários métodos utilitários integrados para os tipos de recuo mais comuns. Modifier.safeDrawingPadding() é um desses métodos, equivalente a Modifier.windowInsetsPadding(WindowInsets.safeDrawing). A tabela a seguir lista os modificadores de padding integrados e o tipo WindowInsets que cada um aplica:

Modifier.safeDrawingPadding()

WindowInsets.safeDrawing

Modifier.safeGesturesPadding()

WindowInsets.safeGestures

Modifier.safeContentPadding()

WindowInsets.safeContent

Modifier.statusBarsPadding()

WindowInsets.statusBars

Modifier.navigationBarsPadding()

WindowInsets.navigationBars

Modifier.captionBarPadding()

WindowInsets.captionBar

Modifier.systemBarsPadding()

WindowInsets.systemBars

Modifier.imePadding()

WindowInsets.ime

Modifier.systemGesturesPadding()

WindowInsets.systemGestures

Modifier.mandatorySystemGesturesPadding()

WindowInsets.mandatorySystemGestures

Modifier.displayCutoutPadding()

WindowInsets.displayCutout

Modifier.waterfallPadding()

WindowInsets.waterfall

Para saber o que cada tipo de inserção abrange, consulte Sobre as inserções de janela.

Modificadores de tamanho de inserção

Os modificadores a seguir aplicam uma quantidade de encartes de janela definindo o tamanho do componente como o tamanho dos encartes:

Modifier.windowInsetsStartWidth(windowInsets: WindowInsets)

Aplica o lado inicial de windowInsets como a largura (como Modifier.width)

Modifier.windowInsetsEndWidth(windowInsets: WindowInsets)

Aplica o lado final de windowInsets como a largura (como Modifier.width)

Modifier.windowInsetsTopHeight(windowInsets: WindowInsets)

Aplica o lado de cima de windowInsets como a altura (como Modifier.height)

Modifier.windowInsetsBottomHeight(windowInsets: WindowInsets)

Aplica o lado de baixo de windowInsets como a altura (como Modifier.height)

Esses modificadores são especialmente úteis para dimensionar um Spacer que ocupa o espaço de inserções:

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

Consumo de encarte

Os modificadores de padding de inserção (windowInsetsPadding e auxiliares como safeDrawingPadding) consomem automaticamente a parte das inserções que são aplicadas como padding. Ao se aprofundar na árvore de composição, os modificadores de padding de encarte aninhados e os modificadores de tamanho de encarte sabem que parte dos encartes já foi consumida por modificadores de padding de encarte externos e evitam usar a mesma parte dos encartes mais de uma vez, o que resultaria em muito espaço extra.

Os modificadores de tamanho de encarte também evitam o uso da mesma parte de encartes mais de uma vez se eles já tiverem sido consumidos. No entanto, como eles mudam de tamanho diretamente, não consomem as inserções.

Como resultado, o aninhamento de modificadores de padding muda automaticamente a quantidade de padding aplicada a cada elemento combinável.

Analisando o mesmo exemplo de LazyColumn de antes, o LazyColumn está sendo redimensionado pelo modificador imePadding. Dentro de LazyColumn, o último item é dimensionado para ter a altura da parte de baixo das barras de sistema:

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

Quando o IME é fechado, o imePadding() não aplica padding. Como resultado, nenhum encarte é consumido, e a altura de Spacer corresponde às barras de sistema inferiores.

Quando o IME é aberto, as inserções dele são animadas para corresponder ao tamanho do IME, e o modificador imePadding() começa a aplicar padding inferior para redimensionar o LazyColumn conforme o IME é aberto. À medida que o modificador imePadding() começa a aplicar o padding inferior, ele também começa a consumir essa quantidade de encartes. Portanto, a altura do Spacer começa a diminuir, já que parte do espaçamento das barras de sistema já foi aplicada pelo modificador imePadding(). Depois que o modificador imePadding() aplica um padding inferior maior que as barras de sistema, a altura de Spacer é zero.

Quando o IME é fechado, as mudanças acontecem ao contrário: o Spacer se expande a partir da altura zero, já que o imePadding() aplica menos do que as barras de sistema inferiores. Por fim, a altura de Spacer corresponde às barras do sistema quando o IME é totalmente animado.

Figura 2. Coluna lenta de ponta a ponta com TextField.

Esse comportamento é alcançado pela comunicação entre todos os modificadores windowInsetsPadding e pode ser influenciado de outras maneiras.

Modifier.consumeWindowInsets(insets: WindowInsets) também consome encartes da mesma forma que Modifier.windowInsetsPadding, mas não aplica os encartes consumidos como padding. Isso é útil em combinação com os modificadores de tamanho de encarte, para indicar aos irmãos que uma determinada quantidade de encartes já foi consumida:

Column(Modifier.verticalScroll(rememberScrollState())) {
    Spacer(Modifier.windowInsetsTopHeight(WindowInsets.systemBars))

    Column(
        Modifier.consumeWindowInsets(
            WindowInsets.systemBars.only(WindowInsetsSides.Vertical)
        )
    ) {
        // content
        Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
    }

    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars))
}

Modifier.consumeWindowInsets(paddingValues: PaddingValues) se comporta de maneira muito semelhante à versão com um argumento WindowInsets, mas usa um PaddingValues arbitrário para consumo. Isso é útil para informar aos filhos quando o padding ou o espaçamento é fornecido por algum outro mecanismo que não sejam os modificadores de padding de encarte, como um Modifier.padding comum ou espaçadores de altura fixa:

Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) {
    // content
    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
}

Nos casos em que os insets de janela brutos são necessários sem consumo, use os valores de WindowInsets diretamente ou use WindowInsets.asPaddingValues() para retornar um PaddingValues dos insets que não são afetados pelo consumo. No entanto, devido às seguintes ressalvas, use os modificadores de padding e tamanho de margens de janela sempre que possível.

Inserções e fases do Jetpack Compose

O Compose usa as APIs principais do AndroidX para atualizar e animar as inserções, que usam as APIs da plataforma que gerenciam as inserções. Devido a esse comportamento da plataforma, as inserções têm uma relação especial com as fases do Jetpack Compose.

O valor das inserções é atualizado depois da fase de composição, mas antes da fase de layout. Isso significa que a leitura do valor de encartes na composição geralmente usa um valor de encartes que está um frame atrasado. Os modificadores integrados descritos nesta página foram criados para atrasar o uso dos valores das inserções até a fase de layout, o que garante que os valores de inserção sejam usados no mesmo frame em que são atualizados.