Configurare gli inserti delle finestre

Per consentire alla tua app il controllo completo della posizione in cui disegna i contenuti, segui questi passaggi di configurazione. Senza questi passaggi, la tua app potrebbe disegnare colori neri o uniformi dietro l'interfaccia utente di sistema o non animarsi in modo sincrono con la tastiera software.

  1. Scegli come target Android 15 (livello API 35) o versioni successive per applicare la visualizzazione edge-to-edge su Android 15 e versioni successive. La tua app viene visualizzata dietro l'interfaccia utente di sistema. Puoi regolare l'interfaccia utente dell'app gestendo gli inset.
  2. Facoltativamente, chiama enableEdgeToEdge() in Activity.onCreate(), che consente alla tua app di essere edge-to-edge nelle versioni precedenti di Android.
  3. Imposta android:windowSoftInputMode="adjustResize" nella voce AndroidManifest.xml della tua attività. Questa impostazione consente all'app di ricevere le dimensioni dell'IME software come margini interni, il che ti aiuta ad applicare il layout e la spaziatura interna appropriati quando l'IME viene visualizzato e scompare nell'app.

    <!-- In your AndroidManifest.xml file: -->
    <activity
      android:name=".ui.MainActivity"
      android:label="@string/app_name"
      android:windowSoftInputMode="adjustResize"
      android:theme="@style/Theme.MyApplication"
      android:exported="true">
    

Utilizzare le API Compose

Una volta che l'attività ha preso il controllo della gestione di tutti gli inserti, puoi utilizzare le API Compose per assicurarti 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.

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 inserti 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à disegnata dietro l'interfaccia utente di sistema per ottenere un effetto da bordo a bordo. Per sfruttare al meglio l'intera finestra, devi perfezionare il punto in cui vengono applicati gli inset su base schermo per schermo o componente per componente.

Tutti questi tipi di rientro vengono animati automaticamente con le animazioni IME di cui è stato eseguito il backporting all'API 21. Di conseguenza, anche tutti i layout che utilizzano questi rientri vengono animati automaticamente al variare dei valori dei rientri.

Esistono due modi principali per utilizzare questi tipi di rientro per regolare i layout composabili: modificatori di spaziatura interna e modificatori delle dimensioni del rientro.

Modificatori di spaziatura interna

Modifier.windowInsetsPadding(windowInsets: WindowInsets) applica i margini della finestra specificati come spaziatura interna, proprio come farebbe Modifier.padding. Ad esempio, Modifier.windowInsetsPadding(WindowInsets.safeDrawing) applica i margini 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 rientro più comuni. Modifier.safeDrawingPadding() è uno di questi metodi, equivalente a Modifier.windowInsetsPadding(WindowInsets.safeDrawing). Esistono modificatori analoghi per gli altri tipi di rientro.

Modificatori delle dimensioni dell'inserto

I seguenti modificatori applicano una quantità di rientri della finestra impostando le dimensioni del componente in modo che corrispondano alle dimensioni dei rientri:

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 un Spacer che occupa lo spazio dei rientri:

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

Consumo inserto

I modificatori di spaziatura interna (windowInsetsPadding e helper come safeDrawingPadding) utilizzano automaticamente la porzione di spaziatura interna applicata come spaziatura interna. Quando si approfondisce l'albero di composizione, i modificatori di spaziatura interna nidificati e i modificatori di dimensione dell'inset sanno che una parte degli inset è già stata utilizzata dai modificatori di spaziatura interna esterni ed evitano di utilizzare la stessa parte degli inset più di una volta, il che comporterebbe uno spazio aggiuntivo eccessivo.

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

Di conseguenza, i modificatori di padding nidificati modificano automaticamente la quantità di padding applicato 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 alcun riempimento, poiché l'IME non ha altezza. Poiché il modificatore imePadding() non applica alcun padding, non vengono utilizzati inset e l'altezza di Spacer corrisponderà alla dimensione del lato inferiore delle barre di sistema.

Quando si apre l'IME, i relativi rientri vengono animati in modo che corrispondano alle dimensioni dell'IME e il modificatore imePadding() inizia ad applicare il padding inferiore per ridimensionare LazyColumn all'apertura dell'IME. Quando il modificatore imePadding() inizia ad applicare il padding inferiore, inizia anche a utilizzare la quantità di insets. Pertanto, l'altezza di Spacer inizia a diminuire, in quanto parte della spaziatura per le barre di sistema è già stata applicata dal modificatore imePadding(). Una volta che il modificatore imePadding() applica un riempimento 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 del lato inferiore delle barre di sistema, finché Spacer non corrisponde all'altezza del lato inferiore delle barre di sistema una volta che l'IME è completamente animato.

Figura 2. Colonna pigra da bordo a bordo 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 padding. È utile in combinazione con i modificatori delle dimensioni dell'inset, per indicare ai fratelli 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 un PaddingValues arbitrario da utilizzare. Ciò è utile per informare i bambini quando il padding o la spaziatura sono forniti da un meccanismo diverso dai modificatori di padding interno, 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 PaddingValues degli inset non interessati dal consumo. Tuttavia, a causa dei seguenti avvisi, preferisci utilizzare i modificatori di padding degli inserti della finestra e i modificatori delle dimensioni degli inserti 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 inserti viene aggiornato dopo la fase di composizione, ma prima della fase di layout. Ciò significa che la lettura del valore degli inserti nella composizione in genere utilizza un valore degli inserti in ritardo di un fotogramma. I modificatori incorporati descritti in questa pagina sono progettati per ritardare l'utilizzo dei valori dei margini interni fino alla fase di layout, il che garantisce che i valori dei margini interni vengano utilizzati nello stesso frame in cui vengono aggiornati.