Configurare gli inserti delle finestre

Una volta che l'attività ha preso il controllo della gestione di tutti gli inset, puoi utilizzare le API Compose per verificare che i contenuti non siano oscurati e che gli elementi interattivi non si sovrappongano all'interfaccia utente di sistema. Queste API sincronizzano anche il layout dell'app con le modifiche all'inset.

Gestire gli inset utilizzando modificatori di spaziatura interna o delle dimensioni

Ad esempio, questo è il metodo più semplice per applicare gli inset ai contenuti dell'intera app:

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

    enableEdgeToEdge()

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

Questo snippet applica gli inset della finestra safeDrawing come spaziatura interna intorno all'intero contenuto dell'app. Sebbene ciò garantisca che gli elementi interattivi non si sovrappongano all'interfaccia utente di sistema, significa anche che nessuna parte dell'app verrà visualizzata dietro l'interfaccia utente di sistema per ottenere un effetto edge-to-edge. Per sfruttare al meglio l'intera finestra, devi perfezionare il punto in cui vengono applicati gli inset schermo per schermo o componente per componente.

Tutti questi tipi di inset vengono animati automaticamente con le animazioni IME, di cui è stato eseguito il backporting nell'API 21. Di conseguenza, anche tutti i layout che utilizzano questi inset vengono animati automaticamente quando cambiano i valori degli inset.

Esistono tre modi per gestire gli inset per regolare i layout degli elementi componibili:

Modificatori di spaziatura interna

Modifier.windowInsetsPadding(windowInsets: WindowInsets) applica gli inset della finestra specificati come spaziatura interna, proprio come farebbe Modifier.padding. Ad esempio, Modifier.windowInsetsPadding(WindowInsets.safeDrawing) applica gli inset di sicurezza per il disegno come spaziatura interna su tutti e quattro i lati.

Esistono anche diversi metodi di utilità integrati per i tipi di inset più comuni. Modifier.safeDrawingPadding() è uno di questi metodi, equivalente a Modifier.windowInsetsPadding(WindowInsets.safeDrawing). Esistono modificatori analoghi per gli altri tipi di inset.

Modificatori delle dimensioni degli inset

I seguenti modificatori applicano una quantità di inset della finestra impostando per il componente dimensioni uguali a quelle degli inset:

Modifier.windowInsetsStartWidth(windowInsets: WindowInsets)

Applica il lato iniziale di windowInsets come larghezza (come Modifier.width)

Modifier.windowInsetsEndWidth(windowInsets: WindowInsets)

Applica il lato finale di windowInsets come larghezza (come Modifier.width)

Modifier.windowInsetsTopHeight(windowInsets: WindowInsets)

Applica il lato superiore di windowInsets come altezza (come Modifier.height)

Modifier.windowInsetsBottomHeight(windowInsets: WindowInsets)

Applica il lato inferiore di windowInsets come altezza (come Modifier.height)

Questi modificatori sono particolarmente utili per dimensionare uno Spacer che occupa lo spazio degli inset:

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

Consumo degli inset

I modificatori di spaziatura interna degli inset (windowInsetsPadding e helper come safeDrawingPadding) consumano automaticamente la porzione degli inset applicata come spaziatura interna. Quando si approfondisce l'albero di composizione, i modificatori di spaziatura interna degli inset nidificati e i modificatori delle dimensioni degli inset sanno che una porzione degli inset è già stata consumata dai modificatori di spaziatura interna degli inset esterni ed evitano di utilizzare la stessa porzione degli inset più di una volta, poiché ciò comporterebbe uno spazio aggiuntivo eccessivo.

I modificatori delle dimensioni degli inset evitano inoltre di consumare la stessa porzione di inset più di una volta se gli inset sono già stati consumati. Tuttavia, poiché modificano direttamente le dimensioni, non consumano gli inset stessi.

Di conseguenza, i modificatori di spaziatura interna nidificati modificano automaticamente la quantità di spaziatura interna applicata a ogni elemento componibile.

Se esaminiamo lo stesso esempio di LazyColumn di prima, le dimensioni di LazyColumn vengono modificate dal modificatore imePadding. All'interno di LazyColumn, l'ultimo elemento è dimensionato in modo da avere l'altezza della parte inferiore delle barre di sistema:

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

Quando l'IME è chiuso, il modificatore imePadding() non applica alcuna spaziatura interna, poiché l'IME non ha nessuna altezza. Poiché il modificatore imePadding() non applica spaziatura interna, non vengono consumati inset e l'altezza di Spacer corrisponderà alla dimensione del lato inferiore delle barre di sistema.

Quando l'IME si apre, i relativi inset vengono animati in modo che corrispondano alle dimensioni dell'IME e il modificatore imePadding() inizia ad applicare la spaziatura interna inferiore per ridimensionare LazyColumn all'apertura dell'IME. Quando il modificatore imePadding() inizia ad applicare la spaziatura interna inferiore, inizia anche a consumare la relativa quantità di inset. Pertanto, l'altezza di Spacer inizia a diminuire, poiché parte della spaziatura per le barre di sistema è già stata applicata dal modificatore imePadding(). Una volta che il modificatore imePadding() applica una spaziatura interna inferiore maggiore delle barre di sistema, l'altezza di Spacer è zero.

Quando l'IME si chiude, le modifiche avvengono al contrario: Spacer inizia a espandersi da un'altezza pari a zero una volta che imePadding() applica meno spaziatura interna rispetto alla parte inferiore delle barre di sistema, finché Spacer non corrisponde all'altezza della parte inferiore delle barre di sistema una volta che l'IME è completamente animato.

Figura 2. LazyColumn edge-to-edge con TextField.

Questo comportamento si ottiene tramite la comunicazione tra tutti i modificatori windowInsetsPadding e può essere influenzato in un paio di altri modi.

Modifier.consumeWindowInsets(insets: WindowInsets) consuma anche gli inset allo stesso modo di Modifier.windowInsetsPadding, ma non applica gli inset consumati come spaziatura interna. Questo comportamento è utile in combinazione con i modificatori delle dimensioni degli inset, per indicare agli elementi di pari livello che una determinata quantità di inset è già stata consumata:

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) si comporta in modo molto simile alla versione con un argomento WindowInsets, ma richiede una classe PaddingValues arbitraria da consumare. Ciò è utile per informare gli elementi secondari quando la spaziatura interna o la spaziatura è fornita da un meccanismo diverso dai modificatori di spaziatura interna degli inset, ad esempio un Modifier.padding ordinario o distanziatori ad altezza fissa:

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

Nei casi in cui sono necessari gli inset grezzi della finestra senza consumo, utilizza direttamente i valori WindowInsets o utilizza WindowInsets.asPaddingValues() per restituire un valore PaddingValues degli inset non interessati dal consumo. Tuttavia, a causa delle seguenti avvertenze, è preferibile utilizzare i modificatori di spaziatura interna degli inset della finestra e i modificatori delle dimensioni degli inset della finestra, ove possibile.

Inset e fasi di Jetpack Compose

Compose utilizza le API AndroidX di base per aggiornare e animare gli inset, che utilizzano le API della piattaforma sottostanti che gestiscono gli inset. A causa del comportamento della piattaforma, gli inset hanno una relazione speciale con le fasi di Jetpack Compose.

Il valore degli inset viene aggiornato dopo la fase di composizione, ma prima della fase di layout. Ciò significa che la lettura del valore degli inset nella composizione generalmente utilizza un valore degli inset che è in ritardo di un frame. I modificatori incorporati descritti in questa pagina sono progettati per ritardare l'utilizzo dei valori degli inset fino alla fase di layout, il che garantisce che i valori degli inset vengano utilizzati nello stesso frame quando vengono aggiornati.