Informazioni su WindowInsetsRulers

WindowInsets è l'API standard in Jetpack Compose per la gestione delle aree dello schermo parzialmente o completamente oscurate dalla UI di sistema. Queste aree includono la barra di stato, la barra di navigazione e la tastiera sullo schermo. In alternativa, puoi trasmettere WindowInsetsRulers predefiniti come SafeDrawing a Modifier.fitInside o Modifier.fitOutside per allineare i contenuti alle barre di sistema e al ritaglio del display o creare WindowInsetsRulers personalizzati.

Vantaggi di WindowInsetsRulers

  • Evita la complessità del consumo: opera durante la fase di posizionamento del layout. Ciò significa che bypassa completamente la catena di consumo degli inset e può sempre fornire le posizioni corrette e assolute delle barre di sistema e dei ritagli del display, indipendentemente da ciò che hanno fatto i layout principali. L'utilizzo dei metodi Modifier.fitInside o Modifier.fitOutside è utile per risolvere i problemi quando i composable antenati consumano in modo errato gli inset.
  • Evita facilmente le barre di sistema: aiuta i contenuti dell'app a evitare le barre di sistema e l'intaglio del display e può essere più semplice dell'utilizzo diretto di WindowInsets.
  • Altamente personalizzabile: gli sviluppatori possono allineare i contenuti a righelli personalizzati e avere un controllo preciso sui layout con layout personalizzati.

Svantaggi di WindowInsetsRulers

  • Non può essere utilizzato per la misurazione: poiché opera durante la fase di posizionamento, le informazioni posizionali che fornisce non sono disponibili durante la fase di misurazione precedente.
  • Potenziale instabilità del layout: ciò può causare arresti anomali se le dimensioni di un layout principale dipendono dalle dimensioni dei relativi elementi secondari. Poiché un elemento secondario che utilizza WindowInsetsRulers potrebbe cambiare posizione o dimensioni durante il posizionamento, può creare un ciclo di layout instabile.

Crea WindowInsetsRulers personalizzato

Puoi allineare i contenuti a righelli personalizzati. Ad esempio, considera il caso d'uso in cui un composable padre gestisce in modo errato gli inset causando problemi di spaziatura interna in un elemento secondario downstream. Sebbene questo problema possa essere risolto in altri modi, ad esempio utilizzando Modifier.fitInside, puoi anche creare un righello personalizzato per allineare con precisione il composable figlio senza dover risolvere il problema nel composable padre upstream, come mostrato nell'esempio e nel video seguenti:

@Composable
fun WindowInsetsRulersDemo(modifier: Modifier) {
    Box(
        contentAlignment = BottomCenter,
        modifier = modifier
            .fillMaxSize()
            // The mistake that causes issues downstream, as .padding doesn't consume insets.
            // While it's correct to instead use .windowInsetsPadding(WindowInsets.navigationBars),
            // assume it's difficult to identify this issue to see how WindowInsetsRulers can help.
            .padding(WindowInsets.navigationBars.asPaddingValues())
    ) {
        TextField(
            value = "Demo IME Insets",
            onValueChange = {},
            modifier = modifier
                // Use alignToSafeDrawing() instead of .imePadding() to precisely place this child
                // Composable without having to fix the parent upstream.
                .alignToSafeDrawing()

            // .imePadding()
            // .fillMaxWidth()
        )
    }
}

fun Modifier.alignToSafeDrawing(): Modifier {
    return layout { measurable, constraints ->
        if (constraints.hasBoundedWidth && constraints.hasBoundedHeight) {
            val placeable = measurable.measure(constraints)
            val width = placeable.width
            val height = placeable.height
            layout(width, height) {
                val bottom = WindowInsetsRulers.SafeDrawing.current.bottom
                    .current(0f).roundToInt() - height
                val right = WindowInsetsRulers.SafeDrawing.current.right
                    .current(0f).roundToInt()
                val left = WindowInsetsRulers.SafeDrawing.current.left
                    .current(0f).roundToInt()
                measurable.measure(Constraints.fixed(right - left, height))
                    .place(left, bottom)
            }
        } else {
            val placeable = measurable.measure(constraints)
            layout(placeable.width, placeable.height) {
                placeable.place(0, 0)
            }
        }
    }
}

Il seguente video mostra un esempio di consumo problematico dell'inserimento IME causato da un elemento principale upstream nell'immagine a sinistra e l'utilizzo di righelli personalizzati per risolvere il problema a destra. Sotto il composable TextField viene mostrato un padding aggiuntivo perché il padding della barra di navigazione non è stato utilizzato dal genitore. L'elemento figlio viene posizionato nella posizione corretta nell'immagine a destra utilizzando un righello personalizzato come mostrato nell'esempio di codice precedente.

Verificare che i genitori siano vincolati

Per utilizzare in sicurezza WindowInsetsRulers, assicurati che il genitore fornisca vincoli validi. Gli elementi principali devono avere una dimensione definita e non possono dipendere dalla dimensione di un elemento secondario che utilizza WindowInsetsRulers. Utilizza fillMaxSize o altri modificatori di dimensioni nei composable principali.

Allo stesso modo, l'inserimento di un componente componibile che utilizza WindowInsetsRulers all'interno di un contenitore scorrevole come verticalScroll può causare un comportamento imprevisto, in quanto il contenitore scorrevole fornisce vincoli di altezza illimitati, che sono incompatibili con la logica del righello.