Le finestre delle app consentono agli utenti di eseguire più app contemporaneamente in finestre ridimensionabili per un'esperienza versatile, proprio come su un desktop.
Nella figura 1 puoi vedere l'organizzazione dello schermo con le app in finestra abilitate. Aspetti da considerare:
- Gli utenti possono eseguire più app una accanto all'altra per utilizzarle contemporaneamente.
- La barra delle app è in una posizione fissa nella parte inferiore del display e mostra le app in esecuzione. Gli utenti possono bloccare le app per accedervi rapidamente.
- La nuova barra dell'intestazione personalizzabile decora la parte superiore di ogni finestra con controlli come Riduci a icona e Ingrandisci.
Per impostazione predefinita, le app si aprono a schermo intero sui tablet Android. Per lanciare un'app in finestra, tieni premuto il punto di trascinamento della finestra nella parte superiore dello schermo e trascinalo all'interno dell'UI, come mostrato nella figura 2.
Quando un'app è aperta nelle finestre, anche le altre app si aprono in finestra.
Gli utenti possono anche richiamare le app in finestra dal menu visualizzato sotto il punto di trascinamento della finestra toccando o facendo clic sul punto di trascinamento, o utilizzando la scorciatoia da tastiera Tasto Meta (Windows, Comando o Ricerca) + Ctrl + Freccia giù.
Gli utenti possono uscire dalle finestre delle app chiudendo tutte le finestre attive o selezionando il punto di trascinamento nella parte superiore di un'app in finestra e trascinando l'app nella parte superiore dello schermo. Anche la scorciatoia da tastiera Meta + H consente di uscire dalle finestre delle app e di eseguire nuovamente le app in modalità a schermo intero.
Per tornare alle finestre delle app, tocca o seleziona il riquadro dello spazio del desktop nella schermata Recenti.
Ridimensionamento e modalità di compatibilità
Nelle finestre delle app, le app con orientamento bloccato possono essere ridimensionate liberamente. Ciò significa che, anche se un'attività è bloccata sull'orientamento verticale, gli utenti possono comunque ridimensionare l'app in una finestra con orientamento orizzontale.
L'UI delle app dichiarate come app non ridimensionabili (ovvero resizeableActivity = false) viene scalata mantenendo lo stesso formato.
Le app della fotocamera che bloccano l'orientamento o sono dichiarate come non ridimensionabili hanno un trattamento speciale per i mirini della fotocamera: la finestra è completamente ridimensionabile, ma il mirino mantiene le stesse proporzioni. Se le app vengono sempre eseguite in verticale o orizzontale, le app vengono impostate come hardcoded o fanno altrimenti ipotesi che portano a errori di calcolo dell'orientamento o delle proporzioni dell'anteprima o dell'immagine acquisita, con conseguenti immagini allungate, laterali o capovolte.
Finché le app non saranno pronte a implementare mirini completamente reattivi, il trattamento speciale offre un'esperienza utente più semplice che mitiga gli effetti causati da ipotesi errate.
Per scoprire di più sulla modalità di compatibilità per le app fotocamera, consulta Modalità di compatibilità del dispositivo.
Inset dell'intestazione personalizzabili
Tutte le app in esecuzione nelle finestre hanno una barra dell'intestazione, anche in modalità immersiva. Puoi personalizzare questa barra per evitare che i contenuti della tua app vengano oscurati e per disegnare elementi UI personalizzati direttamente nello spazio dell'intestazione.
Implementazione
Per disegnare contenuti personalizzati nella barra dell'intestazione, il primo passaggio consiste nel rendere trasparente lo sfondo della barra dell'intestazione. Puoi farlo utilizzando il flag
APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND con
WindowInsetsController.
window.insetsController?.setSystemBarsAppearance( WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND, WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND )
Una volta che la barra dell'intestazione è trasparente, puoi personalizzare l'area dell'intestazione in modo che corrisponda al design della tua app. Utilizza WindowInsets.isCaptionBarVisible per rilevare se la barra è
presente e applicare l'altezza o il padding appropriati al layout.
@OptIn(ExperimentalLayoutApi::class) @Composable fun CaptionBar() { if (WindowInsets.isCaptionBarVisible) { Row( modifier = Modifier .windowInsetsTopHeight(WindowInsets.captionBar) .fillMaxWidth() .background(if (isSystemInDarkTheme()) Color.White else Color.Black), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { Text( text = "Caption Bar Title", style = MaterialTheme.typography.titleMedium, modifier = Modifier.padding(4.dp) ) } } }
setSystemBarsAppearance(appearance,mask): configura lo stile visivo delle barre di sistema. Il primo parametro definisce i flag di aspetto di destinazione, mentre il secondo funge da maschera per controllare quali flag specifici vengono modificati.windowInsetsTopHeight(): imposta automaticamente l'altezza del tuo Composable in modo che corrisponda alla barra dell'intestazione del sistema, aiutando lo sfondo personalizzato a riempire l'area dei sottotitoli codificando i valori dei pixel.WindowInsets.captionBar: fornisce le dimensioni per i controlli delle finestre del computer (Chiudi, Ingrandisci e così via), consentendo alla UI di scalare o nascondersi automaticamente quando si entra o si esce dalla modalità app in finestre.
Per saperne di più, consulta Informazioni sugli insetti delle finestre. Oltre a un titolo, puoi visualizzare altri elementi dell'interfaccia utente nella barra delle didascalie, come schede (come in Google Chrome), barre di ricerca o avatar del profilo.
Interfaccia utente
Per evitare di sovrapporre la tua UI ai pulsanti di sistema, Android 15 fornisce il metodo
WindowInsets#getBoundingRects(). Il metodo restituisce un elenco di oggetti
Rect che rappresentano le aree occupate dagli elementi di sistema. Lo spazio rimanente
nella barra dei sottotitoli codificati è una area di sicurezza in cui puoi inserire in sicurezza contenuti
personalizzati.
Attiva/disattiva l'aspetto degli elementi di sistema dei sottotitoli codificati per i temi chiaro e scuro utilizzando
APPEARANCE_LIGHT_CAPTION_BARS. Accedi agli inserti utilizzando
WindowInsets.Companion.captionBar() in Composizione o
WindowInsets.Type.captionBar() in Visualizzazioni.
Per saperne di più, consulta Informazioni sugli insetti delle finestre.
Supporto per multitasking e multi-istanza
Il multitasking è lo scopo principale delle finestre delle app; consentire più istanze della tua app può aumentare notevolmente la produttività degli utenti.
A partire da Android 15, puoi utilizzare
PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI. Se imposti questa proprietà nel tuo
AndroidManifest.xml, specifichi che l'interfaccia utente di sistema deve fornire opzioni
(come un pulsante "Nuova finestra") per l'avvio dell'app in più istanze.
<application>
<property
android:name="android.window.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI"
android:value="true" />
</application>
Nota:in ambienti con finestre delle app e altri ambienti multi-finestra, le nuove attività si aprono in una nuova finestra, quindi controlla il percorso dell'utente ogni volta che la tua app avvia più attività.
Gestisci le istanze delle app con i gesti di trascinamento
In modalità multi-finestra, gli utenti possono avviare una nuova istanza dell'app trascinando un elemento dell'interfaccia utente (ad esempio una scheda o un documento) fuori dalla finestra dell'app. Gli utenti possono anche spostare gli elementi tra diverse istanze della stessa app.
Trasferire i dati con il trascinamento
Per configurare un elemento componibile come origine di trascinamento per il trascinamento della selezione multi-istanza, che consente agli utenti di trascinare i contenuti in un'altra istanza dell'app o di creare una nuova istanza rilasciando i contenuti in un'area vuota dello schermo, utilizza il modificatore dragAndDropSource. Nella relativa lambda, restituisci
DragAndDropTransferData, passando ClipData che contiene i dati da
trasferire e i flag per configurare il comportamento multi-istanza.
Android 15 introduce due flag chiave per l'utilizzo delle app in finestre in stile desktop e interazioni multi-istanza:
DRAG_FLAG_GLOBAL_SAME_APPLICATION: indica che un'operazione di trascinamento può superare i limiti della finestra (per più istanze della stessa applicazione). QuandostartDragAndDrop()viene chiamato con questo flag impostato, solo le finestre visibili appartenenti alla stessa applicazione possono partecipare all'operazione di trascinamento e ricevere i contenuti trascinati.
Modifier.dragAndDropSource { _ -> DragAndDropTransferData( clipData = ClipData.newPlainText("label", "Your data"), flags = View.DRAG_FLAG_GLOBAL_SAME_APPLICATION ) }
DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG: consente agli utenti di avviare una nuova istanza dell'app rilasciando i contenuti trascinati in un'area vuota dello schermo, se nessuna altra finestra gestisce il rilascio.- Quando utilizzi questo flag, devi fornire un
IntentSenderutilizzandoClipData.Item.Builder#setIntentSender(), che il sistema utilizza per avviare la nuova attività se si verifica un errore irreversibile.
- Quando utilizzi questo flag, devi fornire un
Modifier.dragAndDropSource { _ -> val intent = Intent.makeMainActivity(activity.componentName).apply { putExtra("EXTRA_ITEM_ID", itemId) flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK or Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT } val pendingIntent = PendingIntent.getActivity( activity, 0, intent, PendingIntent.FLAG_IMMUTABLE ) val data = ClipData( "Item $itemId", arrayOf(ClipDescription.MIMETYPE_TEXT_INTENT), ClipData.Item.Builder().setIntentSender(pendingIntent.intentSender).build() ) DragAndDropTransferData( clipData = data, flags = View.DRAG_FLAG_GLOBAL_SAME_APPLICATION or View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG, ) }
Ricevere i dati trasferiti
Per accettare i dati da un'altra istanza, utilizza il modificatore dragAndDropTarget.
Devi richiedere esplicitamente le autorizzazioni se i dati provengono da un'altra istanza o app.
Modifier.dragAndDropTarget( shouldStartDragAndDrop = { event -> event.toAndroidDragEvent().clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN) }, target = object : DragAndDropTarget { override fun onDrop(event: DragAndDropEvent): Boolean { requestDragAndDropPermissions(activity, event.toAndroidDragEvent()) val clipData = event.toAndroidDragEvent().clipData val item = clipData?.getItemAt(0)?.text if (item != null) { // Process the dropped text item here } return item != null } } )
Passaggi chiave:
- Filtro: utilizza
shouldStartDragAndDropper verificare se i dati in entrata (tipo MIME) sono supportati. - Autorizzazioni: chiama
requestDragAndDropPermissions(event)per accedere ai dati. - Handle: estrai i dati nel callback
onDrop.
Altre ottimizzazioni
Personalizza l'avvio delle app e la transizione dalle app dalla visualizzazione a finestre alla modalità a schermo intero.
Specifica dimensioni e posizione predefinite
Non tutte le app hanno bisogno di una finestra grande per offrire valore all'utente, anche se sono ridimensionabili. Puoi
utilizzare il metodo ActivityOptions#setLaunchBounds() per specificare una dimensione e una posizione predefinite all'avvio di un'attività.
Attiva la modalità a schermo intero dallo spazio del desktop
Le app possono passare alla modalità a schermo intero chiamando Activity#requestFullScreenMode(). Il metodo mostra l'app a schermo intero direttamente dalle app in finestra.