L'incorporamento delle attività ottimizza le app sui dispositivi con schermi grandi suddividendo un finestra delle attività dell'applicazione tra due attività o due istanze della stessa attività.
Se la tua app è costituita da più attività, l'incorporamento delle attività ti consente di: offrono un'esperienza utente migliorata su tablet, pieghevoli e dispositivi ChromeOS.
L'incorporamento delle attività non richiede il refactoring del codice. Sei tu a stabilire in che modo la tua app ne visualizza le attività, affiancate o in pila, creando un file XML di configurazione del deployment o effettuando chiamate API Jetpack WindowManager.
Il supporto per schermi di piccole dimensioni viene mantenuto automaticamente. Quando l'app è su un dispositivo con uno schermo piccolo, le attività vengono impilate una sopra l'altra. Attivato schermi di grandi dimensioni, le attività vengono visualizzate una accanto all'altra. Il sistema determina presentazione basata sulla configurazione creata (senza logica di diramazione) obbligatorio.
L'inserimento di attività è compatibile con le modifiche dell'orientamento del dispositivo e funziona perfettamente su dispositivi pieghevoli, impilando e scompilando le attività man mano che il dispositivo si piega e si apre.
L'incorporamento delle attività è supportato sulla maggior parte dei dispositivi con schermi di grandi dimensioni con Android 12L (livello API 32) e superiore.
Finestra attività divisa
L'inserimento di attività suddivide la finestra delle attività dell'app in due contenitori: principale e secondario. I contenitori contengono le attività lanciate dall'attività principale o da altre attività già presenti nei contenitori.
Le attività vengono raggruppate nel container secondario quando vengono avviate e il container secondario è impilato sopra il container principale su schermi di piccole dimensioni in modo che la sovrapposizione delle attività e la navigazione a ritroso siano coerenti con l'ordine dei attività già integrate nella tua app.
L'incorporamento delle attività ti consente di visualizzare le attività in diversi modi. Il tuo l'app può dividere la finestra delle attività avviando due attività una accanto all'altra contemporaneamente:
Oppure, un'attività che occupa l'intera finestra dell'attività può creare una suddivisione per lanciare una nuova attività insieme a:
Le attività che sono già in una suddivisione e condividono una finestra delle attività possono avviare altre attività nei seguenti modi:
A lato sopra un'altra attività:
Di lato e sposta la divisione lateralmente, nascondendo la precedente attività:
Avvia un'attività in primo piano, ovvero nello stesso stack di attività:
Avvia una finestra completa dell'attività nella stessa attività:
Navigazione a ritroso
Tipi di applicazioni diversi possono avere diverse regole di navigazione a ritroso in lo stato della finestra di attività in base alle dipendenze tra le attività o al modo Gli utenti attivano l'evento Indietro, ad esempio:
- Insieme: se le attività sono correlate e non dovrebbe essere mostrata nessuna senza l'altra, è possibile configurare la navigazione a ritroso per terminare entrambe.
- Per farlo da soli: se le attività sono completamente indipendenti, torna alla navigazione su una l'attività non influisce sullo stato di un'altra attività nella finestra dell'attività.
L'evento Indietro viene inviato all'ultima attività attiva quando viene usato il pulsante per la navigazione.
Per la navigazione basata su gesti:
Android 14 (livello API 34) e versioni precedenti: l'evento Indietro viene inviato al attività in cui si è verificato il gesto. Quando gli utenti scorrono dal lato sinistro sullo schermo, l'evento Indietro viene inviato all'attività nel riquadro sinistra della finestra divisa. Quando gli utenti fanno scorrere il dito dal lato destro l'evento Indietro viene inviato all'attività nel riquadro di destra.
Android 15 (livello API 35) e versioni successive
Quando si gestiscono più attività della stessa app, il gesto completa l'attività in primo piano indipendentemente dalla direzione dello scorrimento, offrendo un'esperienza più unificata.
In scenari che coinvolgono due attività da app diverse (overlay), l'evento dorso è diretto all'ultima attività in primo piano, in linea con comportamento della navigazione con pulsanti.
Layout a più riquadri
Jetpack WindowManager consente di creare un'attività di incorporamento di più riquadri
layout su dispositivi con schermi grandi con Android 12L (livello API 32) o versioni successive
su alcuni dispositivi con versioni
precedenti della piattaforma. Le app esistenti basate su più attività anziché su frammenti o layout basati su visualizzazioni, come SlidingPaneLayout
, possono offrire un'esperienza utente migliorata su schermi di grandi dimensioni senza eseguire il refactoring del codice sorgente.
Un esempio comune è la suddivisione in elenco e dettagli. Per garantire un'esperienza di alta qualità presentazione, il sistema avvia l'attività di elenco e quindi l'applicazione avvia immediatamente l'attività dei dettagli. Il sistema di transizione attende fino a quando entrambe le attività non vengono disegnate, quindi le mostra insieme. Per l'utente, le due attività vengono avviate come una sola.
Suddividi attributi
Puoi specificare la proporzione della finestra dell'attività tra i container suddivisi e la disposizione dei container l'uno rispetto all'altro.
Per le regole definite in un file di configurazione XML, imposta i seguenti attributi:
splitRatio
: imposta le proporzioni del contenitore. Il valore è un numero in virgola mobile nell'intervallo aperto (0,0, 1,0).splitLayoutDirection
: specifica la disposizione dei container suddivisi rispetto a un altro. I valori includono:ltr
: da sinistra a destrartl
: da destra a sinistralocale
:ltr
ortl
viene determinato in base all'impostazione internazionale
Per esempi, consulta la sezione Configurazione XML.
Per le regole create utilizzando le API WindowManager, crea un oggetto SplitAttributes
con SplitAttributes.Builder
e chiama i seguenti metodi di compilatore:
setSplitType()
: imposta le proporzioni dei contenitori suddivisi. Consulta:SplitAttributes.SplitType
per argomenti validi, tra cui il valoreSplitAttributes.SplitType.ratio()
.setLayoutDirection()
: imposta il layout dei contenitori. Consulta:SplitAttributes.LayoutDirection
per i possibili valori.
Per esempi, consulta la sezione API WindowManager.
Segnaposto
Le attività segnaposto sono attività secondarie vuote che occupano un'area di suddivisione attività. In ultima analisi, sono pensati per essere sostituiti con un'altra attività che includono contenuti. Ad esempio, un'attività segnaposto potrebbe occupare il lato secondario di un'attività divisa in un layout di elenco dettagliato finché non viene selezionato un elemento dell'elenco, a quel punto un'attività contenente le informazioni dettagliate per l'elemento dell'elenco selezionato sostituisce il segnaposto.
Per impostazione predefinita, il sistema mostra i segnaposto solo quando è presente spazio sufficiente per una suddivisione delle attività. I segnaposto terminano automaticamente quando vengono impostate le dimensioni di visualizzazione la larghezza o l'altezza è troppo ridotta per visualizzare una suddivisione. Quando lo spazio lo consente, il sistema riavvia il segnaposto con uno stato reinizializzato.
Tuttavia, l'attributo stickyPlaceholder
di un metodo SplitPlaceholderRule
o
setSticky()
di SplitPlaceholder.Builder
può sostituire il
comportamento predefinito. Quando l'attributo o il metodo specifica un valore pari a true
, l'oggetto
visualizza il segnaposto come attività di livello più alto nella finestra dell'attività quando
il display viene ridimensionato a un riquadro singolo da un display a due riquadri
(consulta Configurazione di suddivisione per un esempio).
Modifiche alle dimensioni delle finestre
Quando le modifiche alla configurazione del dispositivo riducono la larghezza della finestra delle attività in modo che non abbastanza grande per un layout a più riquadri (ad esempio, quando uno schermo pieghevole di grandi dimensioni il dispositivo si piega dalle dimensioni del tablet a quelle del telefono oppure la finestra dell'app viene ridimensionata in modalità multi-finestra), le attività non segnaposto nel riquadro secondario della finestra delle attività si sovrappone alle attività nel riquadro principale.
Le attività segnaposto vengono mostrate solo quando la larghezza di visualizzazione è sufficiente per una suddivisione. Su schermi più piccoli, il segnaposto viene ignorato automaticamente. Quando l'area di visualizzazione diventa di nuovo sufficientemente grande, il segnaposto viene ricreato. (Vedi nella sezione Segnaposto.
La sovrapposizione delle attività è possibile perché WindowManager ordina le attività nel riquadro secondario sopra le attività nel riquadro principale.
Più attività nel riquadro secondario
L'attività B avvia l'attività C in loco senza ulteriori flag di intent:
generando il seguente ordine z di attività nella stessa attività:
Di conseguenza, in una finestra delle attività più piccola, l'applicazione si riduce a una singola attività con C nella parte superiore dello stack:
Se torni indietro nella finestra più piccola, puoi spostarti tra le attività impilate una sopra l'altra.
Se la configurazione della finestra delle attività viene ripristinata a una dimensione maggiore che può possono ospitare più riquadri, le attività vengono visualizzate di nuovo una accanto all'altra.
Suddivisione in pila
L'attività B inizia l'attività C di lato e sposta la divisione lateralmente:
Il risultato è il seguente ordine Z delle attività nella stessa attività:
In una finestra dell'attività più piccola, l'applicazione si riduce a una singola attività con C attivato in alto:
Orientamento verticale fisso
L'impostazione del file manifest android:screenOrientation consente alle app di limitare l'orientamento verticale o orizzontale. Per migliorare l'esperienza utente su dispositivi con schermi di grandi dimensioni come tablet e pieghevoli, i produttori di dispositivi Gli OEM possono ignorare le richieste di orientamento dello schermo e scrivere l'app in verticale. orientamento orizzontale per le creatività orizzontali e orientamento orizzontale per le creatività verticali.
Analogamente, quando l'inserimento di attività è attivato, gli OEM possono personalizzare i dispositivi per visualizzare le attività in formato letterbox con orientamento verticale fisso in orizzontale su schermi di grandi dimensioni (larghezza ≥ 600 dp). Quando un'attività in modalità Ritratto fissa avvia una seconda attività, il dispositivo può visualizzare le due attività una accanto all'altra in una visualizzazione a due riquadri.
Aggiungi sempre la proprietà android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED
al file manifest dell'app per informare i dispositivi che la tua app supporta l'embedding delle attività (vedi la sezione Configurazione della suddivisione). I dispositivi personalizzati dall'OEM possono quindi determinare se applicare il letterbox alle attività in formato Ritratto fisso.
Configurazione della suddivisione
Le regole di suddivisione configurano le suddivisioni delle attività. Puoi definire le regole di suddivisione in un file di configurazione XML o tramite chiamate all'API WindowManager di Jetpack.
In entrambi i casi, l'app deve accedere alla libreria WindowManager e deve informare il sistema su cui l'app ha implementato l'incorporamento dell'attività.
Procedi nel seguente modo:
Aggiungi la dipendenza più recente della libreria WindowManager a livello di modulo della tua app
build.gradle
, ad esempio:implementation 'androidx.window:window:1.1.0-beta02'
La libreria WindowManager fornisce tutti i componenti necessari per l'embedding delle attività.
Comunica al sistema che la tua app ha implementato l'inserimento di attività.
Aggiungi la proprietà
android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED
all'elemento <application> del file manifest dell'app e imposta il valore su true, ad esempio:<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application> <property android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED" android:value="true" /> </application> </manifest>
Nella versione 1.1.0-alpha06 e successive di WindowManager, le suddivisioni dell'inserimento di attività sono disattivate, a meno che la proprietà non venga aggiunta al manifest e impostata su true.
Inoltre, i produttori di dispositivi utilizzano l'impostazione per attivare funzionalità personalizzate per le app che supportano l'inserimento di attività. Ad esempio, i dispositivi possono applicare il letterbox a un'attività solo in verticale sui display orizzontali per orientarla in vista del passaggio a un layout a due riquadri all'avvio di una seconda attività (vedi Orientamento verticale fisso).
Configurazione XML
Per creare un'implementazione basata su XML dell'inserimento di attività, completa i seguenti passaggi:
Crea un file di risorse XML che:
- Definisce le attività che condividono una suddivisione
- Configura le opzioni di suddivisione
- Crea un segnaposto per il contenitore secondario di la suddivisione quando i contenuti non sono disponibili.
- Specifica le attività che non devono mai far parte di una suddivisione
Ad esempio:
<!-- main_split_config.xml --> <resources xmlns:window="http://schemas.android.com/apk/res-auto"> <!-- Define a split for the named activities. --> <SplitPairRule window:splitRatio="0.33" window:splitLayoutDirection="locale" window:splitMinWidthDp="840" window:splitMaxAspectRatioInPortrait="alwaysAllow" window:finishPrimaryWithSecondary="never" window:finishSecondaryWithPrimary="always" window:clearTop="false"> <SplitPairFilter window:primaryActivityName=".ListActivity" window:secondaryActivityName=".DetailActivity"/> </SplitPairRule> <!-- Specify a placeholder for the secondary container when content is not available. --> <SplitPlaceholderRule window:placeholderActivityName=".PlaceholderActivity" window:splitRatio="0.33" window:splitLayoutDirection="locale" window:splitMinWidthDp="840" window:splitMaxAspectRatioInPortrait="alwaysAllow" window:stickyPlaceholder="false"> <ActivityFilter window:activityName=".ListActivity"/> </SplitPlaceholderRule> <!-- Define activities that should never be part of a split. Note: Takes precedence over other split rules for the activity named in the rule. --> <ActivityRule window:alwaysExpand="true"> <ActivityFilter window:activityName=".ExpandedActivity"/> </ActivityRule> </resources>
Crea un inizializzatore.
Il componente WindowManager
RuleController
analizza il file di configurazione XML e rende le regole disponibili per il sistema. Una libreria Startup di JetpackInitializer
rende disponibile il file XML perRuleController
all'avvio dell'app in modo che le regole siano in vigore all'avvio di qualsiasi attività.Per creare un inizializzatore, segui questi passaggi:
Aggiungi la dipendenza più recente della libreria Jetpack Startup a livello di modulo
build.gradle
, ad esempio:implementation 'androidx.startup:startup-runtime:1.1.1'
Crea una classe che implementi l'interfaccia
Initializer
.L'inizializzatore rende le regole di suddivisione disponibili per
RuleController
per passando l'ID del file di configurazione XML (main_split_config.xml
) al metodoRuleController.parseRules()
.Kotlin
class SplitInitializer : Initializer<RuleController> { override fun create(context: Context): RuleController { return RuleController.getInstance(context).apply { setRules(RuleController.parseRules(context, R.xml.main_split_config)) } } override fun dependencies(): List<Class<out Initializer<*>>> { return emptyList() } }
Java
public class SplitInitializer implements Initializer<RuleController> { @NonNull @Override public RuleController create(@NonNull Context context) { RuleController ruleController = RuleController.getInstance(context); ruleController.setRules( RuleController.parseRules(context, R.xml.main_split_config) ); return ruleController; } @NonNull @Override public List<Class<? extends Initializer<?>>> dependencies() { return Collections.emptyList(); } }
Crea un fornitore di contenuti per le definizioni delle regole.
Aggiungi
androidx.startup.InitializationProvider
al file manifest dell'app come<provider>
. Includi un riferimento all'implementazione dell'inizializzatoreRuleController
,SplitInitializer
:<!-- AndroidManifest.xml --> <provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup" android:exported="false" tools:node="merge"> <!-- Make SplitInitializer discoverable by InitializationProvider. --> <meta-data android:name="${applicationId}.SplitInitializer" android:value="androidx.startup" /> </provider>
InitializationProvider
rileva e inizializzaSplitInitializer
prima viene chiamato il metodoonCreate()
dell'app. Di conseguenza, le regole di suddivisione vengono applicate all'avvio dell'attività principale dell'app.
API WindowManager
Puoi implementare l'inserimento di attività in modo programmatico con alcune chiamate API. Esegui le chiamate nel metodo onCreate()
di una sottoclasse di
Application
per assicurarti che le regole siano in vigore prima del lancio di qualsiasi attività.
Per creare un'attività suddivisa in modo programmatico:
Crea una regola di suddivisione:
Crea una
SplitPairFilter
che identifica le attività che condividono la suddivisione:Kotlin
val splitPairFilter = SplitPairFilter( ComponentName(this, ListActivity::class.java), ComponentName(this, DetailActivity::class.java), null )
Java
SplitPairFilter splitPairFilter = new SplitPairFilter( new ComponentName(this, ListActivity.class), new ComponentName(this, DetailActivity.class), null );
Aggiungi il filtro a un insieme di filtri:
Kotlin
val filterSet = setOf(splitPairFilter)
Java
Set<SplitPairFilter> filterSet = new HashSet<>(); filterSet.add(splitPairFilter);
Crea attributi di layout per la suddivisione:
Kotlin
val splitAttributes: SplitAttributes = SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.33f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) .build()
Java
final SplitAttributes splitAttributes = new SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.33f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) .build();
SplitAttributes.Builder
crea un oggetto contenente layout attributi:setSplitType()
: definisce in che modo l'area di visualizzazione disponibile viene assegnata a ciascun contenitore di attività. Il tipo di suddivisione rapporto specifica la proporzione dell'area di visualizzazione disponibile assegnata container principale; il container secondario occupa il resto l'area di visualizzazione disponibile.setLayoutDirection()
: specifica la disposizione dei contenitori delle attività rispetto l'uno all'altro, prima il contenitore principale.
Crea una
SplitPairRule
:Kotlin
val splitPairRule = SplitPairRule.Builder(filterSet) .setDefaultSplitAttributes(splitAttributes) .setMinWidthDp(840) .setMinSmallestWidthDp(600) .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f)) .setFinishPrimaryWithSecondary(SplitRule.FinishBehavior.NEVER) .setFinishSecondaryWithPrimary(SplitRule.FinishBehavior.ALWAYS) .setClearTop(false) .build()
Java
SplitPairRule splitPairRule = new SplitPairRule.Builder(filterSet) .setDefaultSplitAttributes(splitAttributes) .setMinWidthDp(840) .setMinSmallestWidthDp(600) .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f)) .setFinishPrimaryWithSecondary(SplitRule.FinishBehavior.NEVER) .setFinishSecondaryWithPrimary(SplitRule.FinishBehavior.ALWAYS) .setClearTop(false) .build();
SplitPairRule.Builder
crea e configura la regola:filterSet
: contiene filtri di coppie di suddivisioni che determinano quando applicare la regola identificando le attività che condividono una suddivisione.setDefaultSplitAttributes()
: applica gli attributi di layout alla sezione personalizzata.setMinWidthDp()
: imposta la larghezza di visualizzazione minima (in pixel indipendenti dalla densità, dp) che consente una suddivisione.setMinSmallestWidthDp()
: imposta il valore minimo (in dp) che deve avere la dimensione di visualizzazione più piccola per attivare una suddivisione indipendentemente dall'orientamento del dispositivo.setMaxAspectRatioInPortrait()
: imposta il massimo aspetto di visualizzazione rapporto (altezza:larghezza) con orientamento verticale per quale attività i segmenti di pubblico. Se le proporzioni di un display in formato verticale superano le proporzioni massime, le suddivisioni vengono disattivate indipendentemente dalla larghezza del display. Nota: il valore predefinito è 1,4, il che comporta che le attività occupino l'intera finestra delle attività in orientamento verticale sulla maggior parte dei tablet. Vedi ancheSPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT
esetMaxAspectRatioInLandscape()
. Il valore predefinito per landscape èALWAYS_ALLOW
.setFinishPrimaryWithSecondary()
: imposta il modo in cui il completamento di tutte le attività nel contenitore secondario influisce sulle attività nel contenitore principale.NEVER
indica che il sistema non deve completare le attività principali al termine di tutte le attività nel contenitore secondario (vedi Completare le attività).setFinishSecondaryWithPrimary()
: imposta il modo in cui il completamento di tutte le attività nel contenitore principale influisce sulle attività nel contenitore secondario.ALWAYS
indica che il sistema deve sempre termina le attività nel contenitore secondario quando tutte le attività nella finitura del container principale (vedi Completa le attività).setClearTop()
: specifica se tutte le attività in il container secondario termina quando viene avviata una nuova attività nel container. Un valorefalse
specifica che le nuove attività vengono impilate sulle attività già presenti nel contenitore secondario.
Recupera l'istanza singleton di WindowManager
RuleController
e aggiungi la regola:Kotlin
val ruleController = RuleController.getInstance(this) ruleController.addRule(splitPairRule)
Java
RuleController ruleController = RuleController.getInstance(this); ruleController.addRule(splitPairRule);
Crea un segnaposto per il contenitore secondario quando contenuti non disponibili:
Crea un elemento
ActivityFilter
che identifichi l'attività con cui Il segnaposto condivide una suddivisione della finestra dell'attività:Kotlin
val placeholderActivityFilter = ActivityFilter( ComponentName(this, ListActivity::class.java), null )
Java
ActivityFilter placeholderActivityFilter = new ActivityFilter( new ComponentName(this, ListActivity.class), null );
Aggiungi il filtro a un insieme di filtri:
Kotlin
val placeholderActivityFilterSet = setOf(placeholderActivityFilter)
Java
Set<ActivityFilter> placeholderActivityFilterSet = new HashSet<>(); placeholderActivityFilterSet.add(placeholderActivityFilter);
Crea un
SplitPlaceholderRule
:Kotlin
val splitPlaceholderRule = SplitPlaceholderRule.Builder( placeholderActivityFilterSet, Intent(context, PlaceholderActivity::class.java) ).setDefaultSplitAttributes(splitAttributes) .setMinWidthDp(840) .setMinSmallestWidthDp(600) .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f)) .setFinishPrimaryWithPlaceholder(SplitRule.FinishBehavior.ALWAYS) .setSticky(false) .build()
Java
SplitPlaceholderRule splitPlaceholderRule = new SplitPlaceholderRule.Builder( placeholderActivityFilterSet, new Intent(context, PlaceholderActivity.class) ).setDefaultSplitAttributes(splitAttributes) .setMinWidthDp(840) .setMinSmallestWidthDp(600) .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f)) .setFinishPrimaryWithPlaceholder(SplitRule.FinishBehavior.ALWAYS) .setSticky(false) .build();
SplitPlaceholderRule.Builder
crea e configura la regola:placeholderActivityFilterSet
: contiene filtri di attività che determinare quando applicare la regola identificando le attività con a cui è associata l'attività segnaposto.Intent
: specifica il lancio dell'attività segnaposto.setDefaultSplitAttributes()
: Applica gli attributi di layout alla regola.setMinWidthDp()
: Imposta la larghezza di visualizzazione minima (in pixel indipendenti dalla densità, dp) che consente una suddivisione.setMinSmallestWidthDp()
: imposta il valore minimo (in dp) che deve avere la più piccola delle due dimensioni dello schermo per consentire una suddivisione indipendentemente dall'orientamento del dispositivo.setMaxAspectRatioInPortrait()
: Imposta le proporzioni di visualizzazione massime (altezza:larghezza) in verticale orientamento per il quale vengono visualizzate le suddivisioni delle attività. Nota: il valore predefinito è 1,4, il che fa sì che le attività riempiano la finestra delle attività in formato verticale sulla maggior parte dei tablet. Vedi ancheSPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT
esetMaxAspectRatioInLandscape()
. Il valore predefinito per il formato orizzontale èALWAYS_ALLOW
.setFinishPrimaryWithPlaceholder()
: imposta in che modo il completamento dell'attività segnaposto influisce sulle attività nel contenitore principale. SEMPRE indica che il sistema deve sempre completare le attività nel contenitore principale al termine del segnaposto (vedi Completa attività).setSticky()
: determina se l'attività segnaposto viene visualizzata sopra la serie di attività su display di piccole dimensioni dopo che il segnaposto è stato visualizzato per la prima volta in una suddivisione con una larghezza minima sufficiente.
Aggiungi la regola a WindowManager
RuleController
:Kotlin
ruleController.addRule(splitPlaceholderRule)
Java
ruleController.addRule(splitPlaceholderRule);
Specifica le attività che non devono mai far parte di una suddivisione:
Crea un
ActivityFilter
che identifichi un'attività che deve occupare sempre l'intera area di visualizzazione delle attività:Kotlin
val expandedActivityFilter = ActivityFilter( ComponentName(this, ExpandedActivity::class.java), null )
Java
ActivityFilter expandedActivityFilter = new ActivityFilter( new ComponentName(this, ExpandedActivity.class), null );
Aggiungi il filtro a un insieme di filtri:
Kotlin
val expandedActivityFilterSet = setOf(expandedActivityFilter)
Java
Set<ActivityFilter> expandedActivityFilterSet = new HashSet<>(); expandedActivityFilterSet.add(expandedActivityFilter);
Crea un
ActivityRule
:Kotlin
val activityRule = ActivityRule.Builder(expandedActivityFilterSet) .setAlwaysExpand(true) .build()
Java
ActivityRule activityRule = new ActivityRule.Builder( expandedActivityFilterSet ).setAlwaysExpand(true) .build();
ActivityRule.Builder
crea e configura la regola:expandedActivityFilterSet
: contiene filtri attività che determinano quando applicare la regola identificando le attività da escludere dalle suddivisioni.setAlwaysExpand()
: specifica se l'attività deve riempire l'intera finestra delle attività.
Aggiungi la regola a WindowManager
RuleController
:Kotlin
ruleController.addRule(activityRule)
Java
ruleController.addRule(activityRule);
Incorporamento tra applicazioni
Su Android 13 (livello API 33) e versioni successive, le app possono incorporare attività di altri app. Incorporamento delle attività tra applicazioni o tra UID consente l'integrazione visiva delle attività di più applicazioni Android. La visualizza un'attività dell'app host e un'attività incorporata da un'altra app sullo schermo, affiancata o in alto e in basso, come nelle app singole incorporamento dell'attività.
Ad esempio, l'app Impostazioni potrebbe incorporare l'attività di selezione dello sfondo da l'app BackgroundPicker:
Modello di attendibilità
I processi host che incorporano attività di altre app sono in grado di ridefinire il della presentazione delle attività incorporate, tra cui dimensioni, posizione, ritaglio e e trasparenza. Gli host dannosi possono utilizzare questa funzionalità per ingannare gli utenti e creare clickjacking o altri attacchi di correzione dell'interfaccia utente.
Per evitare l'uso improprio dell'inserimento di attività tra app, Android richiede alle app di attivare la funzionalità per consentire l'inserimento delle loro attività. Le app possono designare gli host come attendibili o non attendibili.
Host attendibili
Per consentire ad altre applicazioni di incorporare e controllare completamente la presentazione dei
di attività dalla tua app, specifica il certificato SHA-256 dell'host
nell'attributo android:knownActivityEmbeddingCerts
della
Elementi <activity>
o <application>
del file manifest della tua app.
Imposta il valore di android:knownActivityEmbeddingCerts
come stringa:
<activity
android:name=".MyEmbeddableActivity"
android:knownActivityEmbeddingCerts="@string/known_host_certificate_digest"
... />
In alternativa, per specificare più certificati, un array di stringhe:
<activity
android:name=".MyEmbeddableActivity"
android:knownActivityEmbeddingCerts="@array/known_host_certificate_digests"
... />
che fa riferimento a una risorsa come la seguente:
<resources>
<string-array name="known_host_certificate_digests">
<item>cert1</item>
<item>cert2</item>
...
</string-array>
</resources>
I proprietari di app possono ottenere un digest del certificato SHA eseguendo il comando Gradle
signingReport
attività. Il digest del certificato è l'impronta SHA-256 senza
i due punti separati. Per saperne di più, vedi Eseguire un report sulla firma e
Autentificare il client.
Host non attendibili
Per consentire a qualsiasi app di incorporare le attività della tua app e controllarne la presentazione,
specifica l'attributo android:allowUntrustedActivityEmbedding
negli
elementi <activity>
o <application>
nel file manifest dell'app, ad esempio:
<activity
android:name=".MyEmbeddableActivity"
android:allowUntrustedActivityEmbedding="true"
... />
Il valore predefinito dell'attributo è false, il che impedisce l'embedding delle attività tra app.
Autenticazione personalizzata
Per ridurre i rischi di incorporamento di attività non attendibili, crea un
meccanismo di autenticazione personalizzato che verifichi l'identità dell'host. Se conosci l'host
, utilizza la libreria androidx.security.app.authenticator
per
autenticarsi. Se l'host autentica dopo aver incorporato la tua attività, puoi
per visualizzare i contenuti effettivi. In caso contrario, puoi informare l'utente che l'azione è stata
non consentito e blocca i contenuti.
Utilizza il metodo ActivityEmbeddingController#isActivityEmbedded()
dal
la libreria Jetpack WindowManager per verificare se un host sta incorporando
dell'attività, ad esempio:
Kotlin
fun isActivityEmbedded(activity: Activity): Boolean { return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity) }
Java
boolean isActivityEmbedded(Activity activity) { return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity); }
Limitazione di dimensioni minime
Il sistema Android applica l'altezza e la larghezza minime specificate nell'elemento <layout>
del file manifest dell'app alle attività incorporate. Se un'applicazione non specifica l'altezza e la larghezza minime, vengono applicati i valori predefiniti del sistema (sw220dp
).
Se l'host tenta di ridimensionare il contenitore incorporato a una dimensione inferiore a quella minimo, il container incorporato si espande per occupare tutti i limiti delle attività.
<activity-alias>
Affinché l'incorporamento di attività attendibili o non attendibili funzioni con il
Elemento <activity-alias>
, android:knownActivityEmbeddingCerts
o
android:allowUntrustedActivityEmbedding
deve essere applicato all'attività target
anziché l'alias. Il criterio che verifica la sicurezza sul server di sistema si basa sui flag impostati sul target, non sull'alias.
Applicazione host
Le applicazioni host implementano l'inserimento di attività cross-app nello stesso modo in cui implementano l'inserimento di attività di singole app. SplitPairRule
e
Oggetti SplitPairFilter
o ActivityRule
e ActivityFilter
per specificare le attività incorporate e la suddivisione delle finestre delle attività. Le regole di suddivisione sono definite
staticamente in XML o in fase di runtime, utilizzando Jetpack
Chiamate API WindowManager.
Se un'applicazione host tenta di incorporare un'attività per la quale non è stata attivata l'incorporamento cross-app, l'attività occupa tutti i limiti delle attività. Di conseguenza, le applicazioni host devono sapere se le attività target consentono incorporamento.
Se un'attività incorporata avvia una nuova attività nella stessa attività e la nuova attività non ha attivato l'incorporamento tra app, l'attività occupa l'intero ambito dell'attività anziché sovrapporla nel contenitore incorporato.
Un'applicazione host può incorporare le proprie attività senza restrizioni purché le attività vengono avviate nella stessa attività.
Esempi di suddivisione
Suddividere lo schermo dalla finestra intera
Non è richiesto alcun refactoring. Puoi definire la configurazione della suddivisione
in modo statico o in fase di runtime, quindi chiama Context#startActivity()
senza
parametri aggiuntivi.
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Dividi per impostazione predefinita
Quando la pagina di destinazione di un'applicazione è progettata per essere suddivisa in due contenitori su schermi di grandi dimensioni, l'esperienza utente è migliore quando entrambe le attività vengono creati e presentati contemporaneamente. Tuttavia, i contenuti potrebbero non essere disponibili per il contenitore secondario della suddivisione finché l'utente non interagisce con l'attività nel contenitore principale (ad esempio, seleziona un elemento da un menu di navigazione). Un'attività segnaposto può colmare il vuoto fino a quando i contenuti non possono essere visualizzati nel contenitore secondario della suddivisione (consulta la sezione Segnaposto).
Per creare una suddivisione con un segnaposto, crea un segnaposto e associalo all'attività principale:
<SplitPlaceholderRule
window:placeholderActivityName=".PlaceholderActivity">
<ActivityFilter
window:activityName=".MainActivity"/>
</SplitPlaceholderRule>
Suddivisione tramite link diretto
Quando un'app riceve un intent, l'attività target può essere mostrata come parte secondaria di una suddivisione attività; Ad esempio, per mostrare un dettaglio schermata con informazioni su un elemento di un elenco. Sui display piccoli, i dettagli vengono visualizzati nella finestra completa dell'attività; sui dispositivi più grandi, accanto all'elenco.
La richiesta di lancio deve essere indirizzata all'attività principale e ai dettagli della destinazione l'attività deve essere lanciata in una suddivisione. Il sistema sceglie automaticamente presentazione corretta, in pila o affiancata, in base alle larghezza di visualizzazione.
Kotlin
override fun onCreate(savedInstanceState Bundle?) { . . . RuleController.getInstance(this) .addRule(SplitPairRule.Builder(filterSet).build()) startActivity(Intent(this, DetailActivity::class.java)) }
Java
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { . . . RuleController.getInstance(this) .addRule(new SplitPairRule.Builder(filterSet).build()); startActivity(new Intent(this, DetailActivity.class)); }
La destinazione del link diretto potrebbe essere l'unica attività che dovrebbe essere disponibile l'utente nello stack di navigazione a ritroso, pertanto è consigliabile evitare l'attività di dettaglio, lasciando solo l'attività principale:
Invece, puoi completare entrambe le attività contemporaneamente utilizzando l'attributo
finishPrimaryWithSecondary
:
<SplitPairRule
window:finishPrimaryWithSecondary="always">
<SplitPairFilter
window:primaryActivityName=".ListActivity"
window:secondaryActivityName=".DetailActivity"/>
</SplitPairRule>
Consulta la sezione Attributi di configurazione.
Più attività in container suddivisi
L'accatastamento di più attività in un contenitore diviso consente agli utenti di accedere a contenuti approfonditi. Ad esempio, con una suddivisione elenco-dettagli, l'utente potrebbe dover accedere a una sezione dei dettagli secondari, ma mantieni attiva l'attività principale:
Kotlin
class DetailActivity { . . . fun onOpenSubDetail() { startActivity(Intent(this, SubDetailActivity::class.java)) } }
Java
public class DetailActivity { . . . void onOpenSubDetail() { startActivity(new Intent(this, SubDetailActivity.class)); } }
L'attività di dettaglio secondario viene posizionata sopra l'attività di dettaglio, nascondendola:
L'utente può quindi tornare al livello di dettaglio precedente tornando indietro tramite la pila:
Sovrapporre le attività una sopra l'altra è il comportamento predefinito quando vengono avviate da un'attività nello stesso contenitore secondario. Attività avviato dal container principale all'interno di un segmento attivo, container secondario in cima all'elenco di attività.
Attività in una nuova attività
Quando le attività in una finestra di attività divisa avviano attività in una nuova attività, la nuova attività è separata dall'attività che include la suddivisione e viene visualizzata in una finestra completa. Nella schermata Recenti vengono visualizzate due attività: l'attività nella suddivisione e la nuova attività.
Sostituzione dell'attività
Le attività possono essere sostituite nello stack del contenitore secondario, ad esempio quando l'attività principale viene utilizzata per la navigazione di primo livello e l'attività secondaria è una destinazione selezionata. Ogni selezione dalla navigazione di livello superiore Avviare una nuova attività nel contenitore secondario e rimuoverla oppure attività che erano presenti in precedenza.
Se l'app non completa l'attività nel contenitore secondario quando modifiche alla selezione della navigazione, la navigazione a ritroso potrebbe creare confusione quando la suddivisione è compresso (quando il dispositivo è chiuso). Ad esempio, se hai un menu nella il riquadro principale e le schermate A e B impilate nel riquadro secondario, quando l'utente Piega lo smartphone, B è sopra il tasto A e A è sopra il menu. Quando l'utente torna indietro da B, compare A al posto del menu.
In questi casi, la schermata A deve essere rimossa dalla pila precedente.
Il comportamento predefinito quando si avvia a lato in un nuovo contenitore su un
la suddivisione esistente consiste nel posizionare i nuovi contenitori secondari in cima e mantenere i vecchi
quelli nello stack posteriore. Puoi configurare le suddivisioni in modo da cancellare la precedente
contenitori secondari con clearTop
e avviano normalmente le nuove attività.
<SplitPairRule
window:clearTop="true">
<SplitPairFilter
window:primaryActivityName=".Menu"
window:secondaryActivityName=".ScreenA"/>
<SplitPairFilter
window:primaryActivityName=".Menu"
window:secondaryActivityName=".ScreenB"/>
</SplitPairRule>
Kotlin
class MenuActivity { . . . fun onMenuItemSelected(selectedMenuItem: Int) { startActivity(Intent(this, classForItem(selectedMenuItem))) } }
Java
public class MenuActivity { . . . void onMenuItemSelected(int selectedMenuItem) { startActivity(new Intent(this, classForItem(selectedMenuItem))); } }
In alternativa, utilizza la stessa attività secondaria e dall'attività principale (menu) invia nuovi intent che risolvono nella stessa istanza, ma attivano un aggiornamento dello stato o dell'interfaccia utente nel contenitore secondario.
Più suddivisioni
Le app possono fornire una navigazione approfondita a più livelli avviando attività aggiuntive sul lato.
Quando un'attività in un contenitore secondario avvia una nuova attività a lato, viene creata una nuova suddivisione sopra quella esistente.
Lo stack posteriore contiene tutte le attività che sono state aperte in precedenza, quindi gli utenti possono vai alla sezione A/B al termine del C.
Per creare una nuova suddivisione, avvia la nuova attività di lato rispetto a quella esistente container secondario. Dichiara le configurazioni per le suddivisioni A/B e B/C e avvia normalmente l'attività C da B:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
<SplitPairFilter
window:primaryActivityName=".B"
window:secondaryActivityName=".C"/>
</SplitPairRule>
Kotlin
class B { . . . fun onOpenC() { startActivity(Intent(this, C::class.java)) } }
Java
public class B { . . . void onOpenC() { startActivity(new Intent(this, C.class)); } }
Reagisci alle modifiche di stato di suddivisione
Attività diverse in un'app possono avere elementi dell'interfaccia utente che svolgono la stessa funzione, ad esempio un controllo che apre una finestra contenente le impostazioni dell'account.
Se due attività che hanno un elemento dell'interfaccia utente in comune sono in una suddivisione, è redundante e forse fonte di confusione mostrare l'elemento in entrambe le attività.
Per sapere quando le attività sono in una suddivisione, controlla il flusso
SplitController.splitInfoList
o registra un ascoltatore con
SplitControllerCallbackAdapter
per le modifiche dello stato della suddivisione. Poi,
regola l'interfaccia utente di conseguenza:
Kotlin
val layout = layoutInflater.inflate(R.layout.activity_main, null) val view = layout.findViewById<View>(R.id.infoButton) lifecycleScope.launch { lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { splitController.splitInfoList(this@SplitDeviceActivity) // The activity instance. .collect { list -> view.visibility = if (list.isEmpty()) View.VISIBLE else View.GONE } } }
Java
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { . . . new SplitControllerCallbackAdapter(SplitController.getInstance(this)) .addSplitListener( this, Runnable::run, splitInfoList -> { View layout = getLayoutInflater().inflate(R.layout.activity_main, null); layout.findViewById(R.id.infoButton).setVisibility( splitInfoList.isEmpty() ? View.VISIBLE : View.GONE); }); }
Le coroutine possono essere lanciate in qualsiasi stato del ciclo di vita, ma in genere vengono lanciate
lo stato STARTED
per risparmiare risorse (vedi Utilizzare le coroutine Kotlin con
componenti sensibili al ciclo di vita per maggiori informazioni).
I richiami possono essere effettuati in qualsiasi stato del ciclo di vita, anche quando un'attività viene interrotta. In genere, gli ascoltatori devono essere registrati in onStart()
e non registrati in onStop()
.
Finestra modale a schermo intero
Alcune attività impediscono agli utenti di interagire con l'applicazione finché viene eseguita l'azione specificata; ad esempio un'attività nella schermata di accesso, schermata di conferma o un messaggio di errore. Le attività modali devono essere impedite da comparire in una suddivisione.
È possibile forzare un'attività a riempire sempre la finestra delle attività utilizzando la configurazione di espansione:
<ActivityRule
window:alwaysExpand="true">
<ActivityFilter
window:activityName=".FullWidthActivity"/>
</ActivityRule>
Termina attività
Gli utenti possono terminare le attività su entrambi i lati del segmento scorrendo dal bordo del display:
Se il dispositivo è configurato per utilizzare il pulsante Indietro anziché la navigazione con i gesti, l'input viene inviato all'attività attiva, ovvero l'attività toccata o avviata per ultima.
L'effetto della terminazione di tutte le attività in un contenitore sul contenitore opposto dipende dalla configurazione della suddivisione.
Attributi di configurazione
Puoi specificare gli attributi delle regole di coppia divisa per configurare il modo in cui le attività su un lato del segmento incidono sulle attività dell'altro lato del la divisione. Gli attributi sono:
window:finishPrimaryWithSecondary
: come completare tutte le attività in il contenitore secondario influisce sulle attività nel contenitore principalewindow:finishSecondaryWithPrimary
- In che modo il completamento di tutte le attività nel contenitore principale influisce sulle attività nel contenitore secondario
I valori possibili degli attributi includono:
always
: completa sempre le attività nel contenitore associatonever
: non completa mai le attività nel contenitore associatoadjacent
: completa le attività nel contenitore associato quando i due contenitori sono visualizzati uno accanto all'altro, ma non quando sono impilzati
Ad esempio:
<SplitPairRule
<!-- Do not finish primary container activities when all secondary container activities finish. -->
window:finishPrimaryWithSecondary="never"
<!-- Finish secondary container activities when all primary container activities finish. -->
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Configurazione predefinita
Quando tutte le attività in un container di una suddivisione terminano, il container rimanente occupa l'intera finestra:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Completare le attività insieme
Completa automaticamente le attività nel contenitore principale quando tutte le attività nella finitura del container secondario:
<SplitPairRule
window:finishPrimaryWithSecondary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Completa automaticamente le attività nel contenitore secondario quando tutte delle attività nella fase di completamento del container principale:
<SplitPairRule
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Terminare le attività insieme al termine di tutte le attività nel contenitore principale o secondario:
<SplitPairRule
window:finishPrimaryWithSecondary="always"
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Completare più attività nei contenitori
Se più attività sono raggruppate in un contenitore diviso, il completamento di un'attività in fondo alla pila non completano automaticamente le attività in alto.
Ad esempio, se nel contenitore secondario si trovano due attività, C sopra la B:
e la configurazione della suddivisione è definita dalla configurazione delle attività A e B:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
se completi l'attività principale, la suddivisione viene mantenuta.
Il completamento dell'attività di base (principale) del contenitore secondario non rimuove le attività al di sopra, pertanto viene mantenuta anche la suddivisione.
Eventuali regole aggiuntive per completare le attività insieme, ad esempio la fine dell'attività secondaria con quella principale, vengono eseguite anche:
<SplitPairRule
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
E quando la suddivisione è configurata per completare l'operazione principale e secondaria insieme:
<SplitPairRule
window:finishPrimaryWithSecondary="always"
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Modifica le proprietà di suddivisione in fase di esecuzione
Le proprietà di una segmentazione attiva e visibile non possono essere modificate. La modifica delle regole di suddivisione influisce su nuovi lanci di attività e nuovi contenitori, ma non sulle suddivisioni esistenti e attive.
Per modificare le proprietà dei segmenti attivi, termina l'attività secondaria oppure le attività del segmento e lanciarle di nuovo con una nuova configurazione.
Proprietà di suddivisione dinamica
Android 15 (livello API 35) e versioni successive supportato da Jetpack WindowManager 1.4 e superiori offrono funzionalità dinamiche che consentono la configurabilità delle attività suddivisioni di incorporamento, tra cui:
- Espansione dei riquadri: un divisore interattivo e trascinabile consente agli utenti di ridimensionare i riquadri in una presentazione divisa.
- Blocco dell'attività: gli utenti possono bloccare i contenuti in un contenitore e isola la navigazione nel contenitore da quella nell'altro contenitore.
- Oscuramento della finestra di dialogo a schermo intero: quando viene visualizzata una finestra di dialogo, le app possono specificare se attenuare l'intera finestra dell'attività o solo il container che ha aperto .
Espansione riquadro
L'espansione del riquadro consente agli utenti di regolare la quantità di spazio sullo schermo assegnata alle due attività in un layout a due riquadri.
Per personalizzare l'aspetto del separatore per finestre e impostare il divisore intervallo trascinabile, procedi nel seguente modo:
Crea un'istanza di
DividerAttributes
Personalizza gli attributi del divisore:
color
: il colore del separatore del riquadro trascinatile.widthDp
:la larghezza del separatore del riquadro trascinabile. Imposta suWIDTH_SYSTEM_DEFAULT
per consentire al sistema di determinare la larghezza del separatore.Intervallo di trascinamento: la percentuale minima dello schermo che ciascun riquadro può occupare. Può variare da 0,33 a 0,66. Imposta su
DRAG_RANGE_SYSTEM_DEFAULT
per consentire al sistema di determinare l'intervallo di trascinamento.
Kotlin
val splitAttributesBuilder: SplitAttributes.Builder = SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.33f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) if (WindowSdkExtensions.getInstance().extensionVersion >= 6) { splitAttributesBuilder.setDividerAttributes( DividerAttributes.DraggableDividerAttributes.Builder() .setColor(getColor(context, R.color.divider_color)) .setWidthDp(4) .setDragRange(DividerAttributes.DragRange.DRAG_RANGE_SYSTEM_DEFAULT) .build() ) } val splitAttributes: SplitAttributes = splitAttributesBuilder.build()
Java
SplitAttributes.Builder splitAttributesBuilder = new SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.33f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT); if (WindowSdkExtensions.getInstance().getExtensionVersion() >= 6) { splitAttributesBuilder.setDividerAttributes( new DividerAttributes.DraggableDividerAttributes.Builder() .setColor(ContextCompat.getColor(context, R.color.divider_color)) .setWidthDp(4) .setDragRange(DividerAttributes.DragRange.DRAG_RANGE_SYSTEM_DEFAULT) .build() ); } SplitAttributes splitAttributes = splitAttributesBuilder.build();
Blocco delle attività
Il blocco attività consente agli utenti di bloccare una delle finestre divisa in modo che l'attività rimane invariata mentre gli utenti navigano all'interno dell'altra finestra. Attività Il blocco offre un'esperienza di multitasking migliorata.
Per attivare il blocco delle attività nella tua app:
Aggiungi un pulsante al file di layout dell'attività che vuoi fissare, per Ad esempio, l'attività di dettaglio di un layout elenco dettagli:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/detailActivity" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" tools:context=".DetailActivity"> <TextView android:id="@+id/textViewItemDetail" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="36sp" android:textColor="@color/obsidian" app:layout_constraintBottom_toTopOf="@id/pinButton" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.appcompat.widget.AppCompatButton android:id="@+id/pinButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/pin_this_activity" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/textViewItemDetail"/> </androidx.constraintlayout.widget.ConstraintLayout>
Nel metodo
onCreate()
dell'attività, imposta un listener di clic sul Pulsante:Kotlin
pinButton = findViewById(R.id.pinButton) pinButton.setOnClickListener { val splitAttributes: SplitAttributes = SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.66f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) .build() val pinSplitRule = SplitPinRule.Builder() .setSticky(true) .setDefaultSplitAttributes(splitAttributes) .build() SplitController.getInstance(applicationContext).pinTopActivityStack(taskId, pinSplitRule) }
Java
Button pinButton = findViewById(R.id.pinButton); pinButton.setOnClickListener( (view) => { SplitAttributes splitAttributes = new SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.66f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) .build(); SplitPinRule pinSplitRule = new SplitPinRule.Builder() .setSticky(true) .setDefaultSplitAttributes(splitAttributes) .build(); SplitController.getInstance(getApplicationContext()).pinTopActivityStack(getTaskId(), pinSplitRule); });
Attiva l'attenuazione a schermo intero
Le attività in genere oscurano il display per attirare l'attenzione su una finestra di dialogo. Per un'esperienza UI unificata, quando viene incorporata un'attività, entrambi i riquadri del display a doppio riquadro devono essere attenuati, non solo il riquadro contenente l'attività che ha aperto la finestra di dialogo.
Con WindowManager 1.4 e versioni successive, l'intera finestra dell'app si attenua per impostazione predefinita quando
(vedi EmbeddingConfiguration.DimAreaBehavior.ON_TASK
).
Per attenuare solo il contenitore dell'attività che ha aperto la finestra di dialogo, usa
EmbeddingConfiguration.DimAreaBehavior.ON_ACTIVITY_STACK
.
Estrae un'attività da una suddivisione a una finestra intera
Crea una nuova configurazione che mostri la finestra completa dell'attività secondaria, quindi riavvia l'attività con un'intenzione che risolva nella stessa istanza.
Verificare il supporto suddiviso in fase di runtime
L'inserimento di attività è supportato su Android 12L (livello API 32) e versioni successive, ma è anche disponibile su alcuni dispositivi con versioni precedenti della piattaforma. Per verificare la disponibilità della funzionalità in fase di esecuzione, utilizza la proprietà SplitController.splitSupportStatus
o il metodo SplitController.getSplitSupportStatus()
:
Kotlin
if (SplitController.getInstance(this).splitSupportStatus == SplitController.SplitSupportStatus.SPLIT_AVAILABLE) { // Device supports split activity features. }
Java
if (SplitController.getInstance(this).getSplitSupportStatus() == SplitController.SplitSupportStatus.SPLIT_AVAILABLE) { // Device supports split activity features. }
Se le suddivisioni non sono supportate, le attività vengono avviate sopra la serie di attività (secondo il modello di embedding non di attività).
Impedire l'override del sistema
I produttori di dispositivi Android (produttori di apparecchiature originali o OEM) possono implementare l'inserimento di attività come funzione del sistema del dispositivo. Il sistema specifica le regole di suddivisione per le app con più attività, sostituendo il comportamento di gestione delle finestre delle app. L'override di sistema forza le app multiattività in un la modalità di incorporamento delle attività definita dal sistema.
L'inserimento di attività di sistema può migliorare la presentazione dell'app tramite layout con più riquadri, ad esempio elenco-dettaglio, senza apportare modifiche all'app. Tuttavia, l'inserimento di attività del sistema potrebbe anche causare layout dell'app errati, bug o conflitti con l'inserimento di attività implementato dall'app.
L'app può impedire o consentire l'inserimento di attività di sistema impostando una proprietà nel file manifest dell'app, ad esempio:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<property
android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE"
android:value="true|false" />
</application>
</manifest>
Il nome della proprietà è definito in Jetpack WindowManager WindowProperties
. Imposta il valore su false
se la tua app implementa l'inserimento di attività o se vuoi impedire al sistema di applicare le sue regole di inserimento di attività alla tua app. Imposta il valore su false
per consentire al sistema di applicare all'app l'inserimento di attività definito dal sistema.
Limitazioni, restrizioni e avvertenze
- Solo l'app host dell'attività, identificata come proprietaria dell'attività principale nell'attività, può organizzare e incorporare altre attività nell'attività. Se le attività che supportano l'inserimento e le suddivisioni vengono eseguite in un'attività appartenente a un'altra applicazione, l'inserimento e le suddivisioni non funzioneranno per queste attività.
- Le attività possono essere organizzate solo all'interno di una singola attività. L'avvio di un'attività in una nuova attività la inserisce sempre in una nuova finestra espansa al di fuori di eventuali suddivisioni esistenti.
- Solo le attività nello stesso processo possono essere organizzate e suddivise. Il callback
SplitInfo
registra solo le attività che appartengono allo stesso processo, poiché non è possibile conoscere le attività in processi diversi. - Ogni coppia o singola regola di attività si applica solo ai lanci di attività che dopo la registrazione della regola. Al momento non è possibile aggiornare le suddivisioni esistenti o le relative proprietà visive.
- La configurazione del filtro delle coppie divise deve corrispondere alle intenzioni utilizzate per il lancio completo delle attività. La corrispondenza avviene nel momento in cui un nuovo viene avviata dal processo di richiesta, quindi potrebbe non essere a conoscenza dei componenti, che verranno risolti in una fase successiva del processo di sistema quando intent impliciti. Se il nome di un componente non è noto al momento del lancio, viene è possibile utilizzare il carattere jolly ("*/*") e l'applicazione dei filtri per l'azione intent.
- Al momento non è possibile spostare le attività tra i contenitori o all'interno e all'esterno delle suddivisioni dopo la loro creazione. Le suddivisioni vengono create soltanto nella libreria WindowManager, quando vengono avviate nuove attività con regole corrispondenti e le suddivisioni vengono eliminate quando l'ultima attività in un container di suddivisione completato.
- Le attività possono essere riavviate quando la configurazione cambia, quindi quando una suddivisione viene creato o rimosso e i limiti di attività cambiano, l'attività può completando la distruzione dell'istanza precedente e la creazione uno nuovo. Di conseguenza, gli sviluppatori di app devono fare attenzione a operazioni come il lancio di nuove attività dai callback del ciclo di vita.
- I dispositivi devono includere l'interfaccia delle estensioni delle finestre per supportare l'attività incorporamento. Quasi tutti i dispositivi con schermo di grandi dimensioni con Android 12L (livello API 32) o successive includono l'interfaccia. Tuttavia, alcuni dispositivi con schermi grandi non sono in grado di eseguire più attività non includere la finestra l'interfaccia delle estensioni. Se un dispositivo con schermo grande non supporta la modalità multi-finestra potrebbe non supportare l'incorporamento delle attività.
Risorse aggiuntive
- Codelab:
- Percorso di apprendimento: Incorporazione delle attività
- App di esempio: activity-embedding