La piattaforma Android è responsabile del disegno dell'interfaccia utente di sistema, ad esempio la barra di stato e la barra di navigazione. Questa UI di sistema viene visualizzata indipendentemente dall'app in uso dall'utente.
WindowInsets
fornisce informazioni sull'UI
di sistema per assicurarti che l'app venga disegnata nell'area corretta e che la tua UI non sia oscurata
dall'UI di sistema.
Su Android 14 (livello API 34) e versioni precedenti, l'interfaccia utente dell'app non viene disegnata sotto le barre di sistema e i ritagli dello schermo per impostazione predefinita.
Su Android 15 (livello API 35) e versioni successive, l'app viene disegnata sotto le barre di sistema e mostra i ritagli quando ha come target l'SDK 35. Ciò si traduce in un'esperienza utente più fluida e consente alla tua app di sfruttare al meglio lo spazio della finestra a sua disposizione.
La visualizzazione dei contenuti dietro l'interfaccia utente di sistema è chiamata passaggio a schermo intero. In questa pagina scoprirai i diversi tipi di inserimenti, come passare da un'app a schermo intero e come utilizzare le API di inserimenti per animare l'interfaccia utente e assicurarti che i contenuti dell'app non vengano oscurati dagli elementi dell'interfaccia utente di sistema.
Nozioni di base sugli intestazioni
Quando un'app è a schermo intero, devi assicurarti che le interazioni e i contenuti importanti non siano oscurati dall'interfaccia utente di sistema. Ad esempio, se un pulsante è collocato dietro la barra di navigazione, l'utente potrebbe non essere in grado di fare clic su di esso.
Le dimensioni dell'interfaccia utente di sistema e le informazioni sulla posizione in cui è posizionata vengono specificate tramite gli inserti.
Ogni parte dell'interfaccia utente di sistema ha un tipo di insenatura corrispondente che descrive le sue dimensioni e la sua posizione. Ad esempio, gli inserti della barra di stato forniscono le dimensioni e la posizione della barra di stato, mentre gli inserti della barra di navigazione forniscono le dimensioni e la posizione della barra di navigazione. Ogni tipo di insenatura è costituito da quattro dimensioni in pixel: superiore, sinistra, destra e inferiore. Queste dimensioni specificano quanto si estende l'interfaccia utente di sistema dai lati corrispondenti della finestra dell'app. Per evitare sovrapposizioni con questo tipo di UI di sistema, l'UI dell'app deve essere rientrata di questa quantità.
Questi tipi di intestazioni Android integrate sono disponibili tramite WindowInsets
:
Gli inserti che descrivono le barre di stato. Si tratta delle barre dell'interfaccia utente di sistema in alto contenenti icone di notifica e altri indicatori. |
|
La barra di stato si inserisce quando è visibile. Se al momento le barre di stato sono nascoste (a causa dell'attivazione della modalità a schermo intero immersiva), gli inserti della barra di stato principale saranno vuoti, ma non vuoti. |
|
Gli inserti che descrivono le barre di navigazione. Si tratta delle barre dell'interfaccia utente di sistema sul lato sinistro, destro o inferiore del dispositivo, che descrivono le icone della barra delle app o di navigazione. Questi possono cambiare in fase di esecuzione in base al metodo di navigazione preferito dall'utente e all'interazione con la barra delle app. |
|
La barra di navigazione si inserisce quando è visibile. Se al momento le barre di navigazione sono nascoste (a causa dell'attivazione della modalità a schermo intero immersiva), gli inserti della barra di navigazione principale saranno vuoti, ma non vuoti. |
|
L'inserimento che descrive la decorazione della finestra dell'interfaccia utente di sistema se si trova in una finestra di forma libera, ad esempio la barra del titolo superiore. |
|
La barra dei sottotitoli codificati si inserisce quando sono visibili. Se le barre dei sottotitoli codificati sono attualmente nascoste, gli inserti della barra dei sottotitoli codificati principali saranno vuoti, ma questi inserti non saranno vuoti. |
|
L'unione degli inserti della barra di sistema, che include le barre di stato, le barre di navigazione e la barra delle scritte. |
|
La barra di sistema si inserisce quando è visibile. Se le barre di sistema sono attualmente nascoste (a causa dell'attivazione della modalità a schermo intero immersiva), gli inserti della barra di sistema principale saranno vuoti, ma questi inserti non saranno vuoti. |
|
Gli inserti che descrivono lo spazio occupato dalla tastiera software nella parte inferiore. |
|
Gli inserti che descrivono lo spazio occupato dalla tastiera software prima dell'animazione della tastiera corrente. |
|
Gli inserti che descrivono la quantità di spazio che la tastiera software occuperà dopo l'animazione della tastiera corrente. |
|
Un tipo di intestazioni che descrivono informazioni più dettagliate sull'interfaccia utente di navigazione, indicando la quantità di spazio in cui i "tocchi" verranno gestiti dal sistema e non dall'app. Per le barre di navigazione trasparenti con navigazione tramite gesti, alcuni elementi dell'app possono essere toccati tramite l'interfaccia utente di navigazione del sistema. |
|
Gli elementi toccabili rientrano quando sono visibili. Se gli elementi toccabili sono attualmente nascosti (a causa dell'attivazione della modalità a schermo intero immersiva), gli inserti dell'elemento tocabile principale saranno vuoti, ma questi inserti non saranno vuoti. |
|
Gli inserti che rappresentano la quantità di inserti in cui il sistema intercetta i gesti per la navigazione. Le app possono specificare manualmente la gestione di un numero limitato di questi gesti tramite |
|
Un sottoinsieme di gesti di sistema che verranno sempre gestiti dal sistema e che non possono essere disattivati tramite |
|
Gli inserti che rappresentano la quantità di spaziatura necessaria per evitare la sovrapposizione con un ritaglio del display (tacca o foro). |
|
Gli inserti che rappresentano le aree curve di un grafico a cascata. Un display a cascata presenta aree curve lungo i bordi dello schermo, dove lo schermo inizia a avvolgersi lungo i lati del dispositivo. |
Questi tipi sono riassunti in tre tipi di intestazioni "sicure" che assicurano che i contenuti non vengano nascosti:
Questi tipi di intestazioni "sicure" proteggono i contenuti in modi diversi, in base agli intestazioni della piattaforma di base:
- Utilizza
WindowInsets.safeDrawing
per proteggere i contenuti che non devono essere disegnati sotto l'interfaccia utente di sistema. Questo è l'utilizzo più comune degli inserti: per impedire di disegnare contenuti oscurati dall'interfaccia utente di sistema (parzialmente o completamente). - Usa
WindowInsets.safeGestures
per proteggere i contenuti con i gesti. In questo modo, si evitano conflitti tra i gesti di sistema e quelli delle app (ad esempio quelli per i riquadri inferiori, i caroselli o i giochi). - Utilizza
WindowInsets.safeContent
come combinazione diWindowInsets.safeDrawing
eWindowInsets.safeGestures
per assicurarti che i contenuti non abbiano sovrapposizioni visive e non sovrapposizioni di gesti.
Configurazione degli inserti
Per consentire alla tua app il controllo completo sulla posizione in cui vengono estratti i contenuti, segui questi passaggi di configurazione. Senza questi passaggi, l'app potrebbe disegnare colori neri o a tinta unita dietro l'interfaccia utente di sistema o non animarsi in modo sincrono con la tastiera software.
- Scegli come target l'SDK 35 o versioni successive per applicare la modalità edge-to-edge su Android 15 e versioni successive. L'app viene visualizzata dietro l'interfaccia utente di sistema. Puoi modificare l'interfaccia utente dell'app gestendo gli inset.
- Facoltativamente, chiama
enableEdgeToEdge()
inActivity.onCreate()
, che consente alla tua app di essere edge-to-edge sulle versioni precedenti di Android. Imposta
android:windowSoftInputMode="adjustResize"
nella voceAndroidManifest.xml
della sezione Attività. Questa impostazione consente alla tua app di ricevere le dimensioni dell'IME software come inserimenti, che puoi utilizzare per aggiungere spazi e impaginare i contenuti in modo appropriato quando l'IME viene visualizzato e scompare nella tua 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">
Componi API
Una volta che l'attività ha assunto il controllo della gestione di tutti gli insert, 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 dell'inserimento.
Ad esempio, questo è il metodo più semplice per applicare gli insert 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 intorno all'intero contenuto dell'app. Sebbene ciò garantisca che gli elementi interattivi non si sovrappongano all'interfaccia utente di sistema, significa anche che nessuno degli elementi dell'app verrà visualizzato dietro l'interfaccia utente di sistema per ottenere un effetto da bordo a bordo. Per utilizzare appieno l'intera
finestra, devi ottimizzare la posizione in cui vengono applicati gli inserti su ogni schermo
o componente.
Tutti questi tipi di intestazioni vengono animati automaticamente con le animazioni IME implementate nell'API 21. Di conseguenza, tutti i layout che utilizzano questi inserimenti vengono anche animati automaticamente quando cambiano i valori degli inserimenti.
Esistono due modi principali per utilizzare questi tipi di rientranze per modificare i layout di Composable: modificatori di spaziatura interna e modificatori delle dimensioni dell'inserimento.
Modificatori di spaziatura interna
Modifier.windowInsetsPadding(windowInsets: WindowInsets)
applica i rientrati della finestra specificati come spaziatura interna, proprio come farebbe Modifier.padding
.
Ad esempio, Modifier.windowInsetsPadding(WindowInsets.safeDrawing)
applica gli inserti di disegno sicuri come spaziatura su tutti e quattro i lati.
Esistono anche diversi metodi di utilità integrati per i tipi di intestazione più comuni.
Modifier.safeDrawingPadding()
è uno di questi metodi, equivalente a
Modifier.windowInsetsPadding(WindowInsets.safeDrawing)
. Esistono modi di modificare analoghi per gli altri tipi di intestazione.
Modificatori delle dimensioni dell'inserimento
I seguenti modificatori applicano una quantità di rientranze della finestra impostando le dimensioni del componente sulle dimensioni dei rientranze:
Applica il lato iniziale di windowInsets come larghezza (ad es. |
|
Applica il lato di fine di windowInsets come larghezza (ad esempio |
|
Applica il lato superiore di windowInsets come altezza (ad es. |
|
|
Applica il lato inferiore di windowInsets come altezza (ad esempio |
Questi modificatori sono particolarmente utili per determinare le dimensioni di un Spacer
che occupa lo spazio degli inserti:
LazyColumn( Modifier.imePadding() ) { // Other content item { Spacer( Modifier.windowInsetsBottomHeight( WindowInsets.systemBars ) ) } }
Consumo in un intestazione
I modificatori di spaziatura interna (windowInsetsPadding
e helper come
safeDrawingPadding
) utilizzano automaticamente la parte degli inserti che viene applicata come spaziatura interna. Quando entri più in profondità nell'albero della composizione, i modificatori di spaziatura interna nidificati e i modificatori delle dimensioni dell'inserimento interno sanno che alcune parti degli inserimenti sono già state utilizzate dai modificatori di spaziatura interna esterna ed evitano di utilizzare la stessa parte degli inserimenti più di una volta, il che comporterebbe troppo spazio aggiuntivo.
I modificatori delle dimensioni degli inserti evitano inoltre di utilizzare la stessa porzione di inserti più di una volta se gli inserti sono già stati utilizzati. Tuttavia, poiché cambiano direttamente le loro dimensioni, non consumano gli insetti stessi.
Di conseguenza, l'annidamento dei modificatori di spaziatura modifica automaticamente la quantità di spaziatura applicata a ogni composable.
Se guardiamo lo stesso esempio di LazyColumn
di prima, LazyColumn
viene ridimensionato dal modificatore imePadding
. All'interno di LazyColumn
, l'ultimo elemento è impostato sull'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 spaziatura interna, poiché
l'IME non ha altezza. Poiché il modificatore imePadding()
non applica spaziatura interna,
non vengono utilizzati inset e l'altezza di Spacer
sarà uguale alla dimensione
del lato inferiore delle barre di sistema.
Quando si apre l'IME, gli inserti dell'IME vengono animati in modo da adattarsi alle dimensioni dell'IME e il modificatore imePadding()
inizia ad applicare il padding inferiore per ridimensionare imePadding()
man mano che l'IME si apre.LazyColumn
Quando il modificatore imePadding()
inizia ad applicare il padding inferiore, inizia anche a consumare questa quantità di rientri. Pertanto, l'altezza del Spacer
inizia a diminuire, poiché parte della spaziatura per le barre del sistema è già stata applicata dal modificatore imePadding()
. Una volta che il modificatore imePadding()
applica un valore di spaziatura inferiore maggiore rispetto alle barre di sistema, l'altezza di Spacer
è pari a zero.
Quando l'IME si chiude, le modifiche avvengono in ordine inverso: Spacer
inizia a espandersi da un'altezza pari a zero quando imePadding()
viene applicato meno del lato inferiore delle barre di sistema, fino a quando Spacer
non corrisponde all'altezza del lato inferiore delle barre di sistema una volta che l'IME è completamente animato.
Questo comportamento viene ottenuto tramite la comunicazione tra tutti i modificatori windowInsetsPadding
e può essere influenzato in altri modi.
Anche Modifier.consumeWindowInsets(insets: WindowInsets)
utilizza gli inserti allo stesso modo di Modifier.windowInsetsPadding
, ma non li applica come spaziatura interna. Questo è utile in combinazione con i modificatori di dimensione degli inset per indicare ai fratelli che è stata già consumata una certa quantità di inset:
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 consumare. Questo è utile per informare
i bambini quando lo spazio interno o lo spazio viene fornito da un altro meccanismo rispetto ai modifi
catori di spaziatura interna, ad esempio un normale Modifier.padding
o spaziature di altezza fissa:
Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) { // content Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime)) }
Se sono necessari gli intarsi della finestra non elaborati senza consumo, utilizza direttamente i valori WindowInsets
o WindowInsets.asPaddingValues()
per restituire un PaddingValues
degli intarsi non interessati dal consumo.
Tuttavia, a causa dei limiti riportati di seguito, preferite utilizzare i modificatori di spaziatura interna della finestra e di dimensioni della finestra se possibile.
Inset e fasi di Jetpack Compose
Compose utilizza le API di base di AndroidX per aggiornare e animare gli inserti, che utilizzano le API di piattaforma sottostanti che gestiscono gli inserti. A causa di questo comportamento della piattaforma, gli inset hanno un rapporto speciale con le fasi di Jetpack Compose.
Il valore degli insert 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 integrati descritti in questa pagina sono progettati per ritardare l'utilizzo dei valori degli inserti fino alla fase di layout, il che garantisce che i valori degli inserti vengano utilizzati nello stesso frame man mano che vengono aggiornati.
Animazioni dell'IME della tastiera con WindowInsets
Puoi applicare Modifier.imeNestedScroll()
a un contenitore con scorrimento per aprire e chiudere automaticamente l'IME quando scorri fino in fondo al contenitore.
class WindowInsetsExampleActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) WindowCompat.setDecorFitsSystemWindows(window, false) setContent { MaterialTheme { MyScreen() } } } } @OptIn(ExperimentalLayoutApi::class) @Composable fun MyScreen() { Box { LazyColumn( modifier = Modifier .fillMaxSize() // fill the entire window .imePadding() // padding for the bottom for the IME .imeNestedScroll(), // scroll IME at the bottom content = { } ) FloatingActionButton( modifier = Modifier .align(Alignment.BottomEnd) .padding(16.dp) // normal 16dp of padding for FABs .navigationBarsPadding() // padding for navigation bar .imePadding(), // padding for when IME appears onClick = { } ) { Icon(imageVector = Icons.Filled.Add, contentDescription = "Add") } } }
Supporto dell'inserimento per i componenti Material 3
Per semplicità d'uso, molti dei composabili Material 3 integrati
(androidx.compose.material3
)
gestiscono autonomamente gli inserti, in base alla modalità di posizionamento dei composabili nell'app
in base alle specifiche di Material.
Composabili per la gestione degli intestazioni
Di seguito è riportato un elenco dei componenti Material che gestiscono automaticamente gli inserti.
Barre delle app
TopAppBar
/SmallTopAppBar
/CenterAlignedTopAppBar
/MediumTopAppBar
/LargeTopAppBar
: applica i lati superiore e orizzontale delle barre di sistema come spaziatura interna, poiché vengono utilizzati nella parte superiore della finestra.BottomAppBar
: applica i lati inferiore e orizzontale delle barre di sistema come spaziatura interna.
Contenitori di contenuti
ModalDrawerSheet
/DismissibleDrawerSheet
/PermanentDrawerSheet
(contenuti all'interno di un riquadro di navigazione modale): applica i rientri verticali e iniziale ai contenuti.ModalBottomSheet
: applica gli inserti inferiori.NavigationBar
: applica i rientri bottom e horizontal.NavigationRail
: applica gli inserti verticale e inizio.
Scaffold
Per impostazione predefinita,
Scaffold
fornisce gli insert come parametro paddingValues
da consumare e utilizzare.
Scaffold
non applica gli insert ai contenuti; questa responsabilità è tua.
Ad esempio, per utilizzare questi intestazioni con un LazyColumn
all'interno di un Scaffold
:
Scaffold { innerPadding -> // innerPadding contains inset information for you to use and apply LazyColumn( // consume insets as scaffold doesn't do it by default modifier = Modifier.consumeWindowInsets(innerPadding), contentPadding = innerPadding ) { items(count = 100) { Box( Modifier .fillMaxWidth() .height(50.dp) .background(colors[it % colors.size]) ) } } }
Sostituire gli inserti predefiniti
Puoi modificare il parametro windowInsets
passato al composable per
configurarne il comportamento. Questo parametro può essere un tipo diverso di rientranza della finestra da applicare oppure può essere disattivato passando un'istanza vuota:WindowInsets(0, 0, 0, 0)
.
Ad esempio, per disattivare la gestione dell'inserimento su
LargeTopAppBar
,
imposta il parametro windowInsets
su un'istanza vuota:
LargeTopAppBar( windowInsets = WindowInsets(0, 0, 0, 0), title = { Text("Hi") } )
Interoperabilità con gli inserti del sistema di visualizzazione
Potresti dover ignorare gli inserimenti predefiniti quando nella schermata sono presenti sia le visualizzazioni sia il codice di composizione nella stessa gerarchia. In questo caso, devi indicare esplicitamente quale deve utilizzare gli insert e quale ignorarli.
Ad esempio, se il layout più esterno è un layout di vista Android, devi utilizzare gli inserti nel sistema di visualizzazione e ignorarli per Compose.
In alternativa, se il layout più esterno è un composable, devi utilizzare gli inserti in Compose e aggiungere spaziatura ai composable AndroidView
di conseguenza.
Per impostazione predefinita, ogni ComposeView
consuma tutti gli insetti al livello di consumo WindowInsetsCompat
. Per modificare questo comportamento predefinito, imposta
ComposeView.consumeWindowInsets
su false
.
Protezione della barra di sistema
Una volta che la tua app ha come target l'SDK 35 o versioni successive, viene applicata la modalità edge-to-edge. La barra di stato di sistema e le barre di navigazione tramite gesti sono trasparenti, ma la barra di navigazione con tre pulsanti è traslucida.
Per rimuovere la protezione dello sfondo di navigazione con tre pulsanti traslucidi predefinita, imposta Window.setNavigationBarContrastEnforced
su false
.
Risorse
- Barre di sistema Android, linee guida per la progettazione delle barre di sistema
- Ora su Android: un'app Android completamente funzionale creata interamente con Kotlin e Jetpack Compose.
- Gestire le applicazioni a tutto schermo in Android 15: un codelab che illustra l'applicazione a tutto schermo in Android 15
- Suggerimenti per la gestione degli inserti per l'applicazione forzata del formato edge-to-edge di Android 15
- Visualizzare l'anteprima e testare l'interfaccia utente edge-to-edge dell'app
- 3 modi per migliorare l'esperienza con le app per Android: a schermo intero, tasto Indietro predittivo e Riepilogo: un video di YouTube che parla dell'applicazione forzata dello schermo intero in Android 15
- Ritratti a tutto schermo e ingrandimenti | Suggerimenti per la composizione: un video di YouTube che mostra come gestire gli ingrandimenti per scattare foto a tutto schermo
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Componenti e layout di Material
- Eseguire la migrazione di
CoordinatorLayout
a Scrivi - Altre considerazioni