Durch das Einbetten von Aktivitäten werden Apps auf Geräten mit großem Display optimiert, indem das Aufgabenfenster einer Anwendung zwischen zwei Aktivitäten oder zwei Instanzen derselben Aktivität aufgeteilt wird.
Wenn Ihre App aus mehreren Aktivitäten besteht, können Sie mithilfe von eingebetteten Aktivitäten die Nutzerfreundlichkeit auf Tablets, faltbaren Geräten und ChromeOS-Geräten verbessern.
Für das Einbetten von Aktivitäten ist kein Code-Refactoring erforderlich. Sie bestimmen, wie Ihre App seine Aktivitäten nebeneinander oder gestapelt anzeigen, indem Sie eine XML-Datei oder Jetpack WindowManager-API-Aufrufe ausführen.
Die Unterstützung für kleine Bildschirme wird automatisch beibehalten. Wenn Ihre App auf einem Gerät mit kleinem Bildschirm haben, sind die Aktivitäten übereinander gestapelt. Auf großen Bildschirmen werden Aktivitäten nebeneinander angezeigt. Das System bestimmt, Präsentation basierend auf der von Ihnen erstellten Konfiguration – keine Verzweigungslogik erforderlich.
Die Aktivitäts-Embeddings passen sich an die Geräteausrichtung an und funktionieren nahtlos auf faltbaren Geräten. Aktivitäten werden beim Zusammen- und Aufklappen des Geräts gestapelt und wieder entfernt.
Das Einbetten von Aktivitäten wird auf den meisten Geräten mit großem Bildschirm und Android 12L (API-Level 32) und höher unterstützt.
Aufgabenfenster teilen
Die Aktivitätseinbettung teilt das App-Aufgabenfenster in zwei Container auf: primären und sekundär. Die Container enthalten Aktivitäten, die aus der Hauptaktivität oder aus anderen Aktivitäten, die bereits in den Containern vorhanden sind.
Aktivitäten werden beim Starten im sekundären Container gestapelt. Auf kleinen Bildschirmen wird der sekundäre Container auf dem primären Container gestapelt. So entsprechen das Stapeln von Aktivitäten und die Rücknavigation der Reihenfolge der Aktivitäten, die bereits in Ihrer App implementiert sind.
Die Einbettung von Aktivitäten ermöglicht es Ihnen, Aktivitäten auf verschiedene Weise darzustellen. Ihr App kann das Aufgabenfenster teilen, indem zwei Aktivitäten nebeneinander gestartet werden gleichzeitig:
Sie können auch eine neue Aktivität neben einer Aktivität starten, die das gesamte Aufgabenfenster belegt, um eine Aufteilung zu erstellen:
Aktivitäten, die sich bereits in einer geteilten Ablage befinden und ein Aufgabenfenster teilen, können gestartet werden auf folgende Arten ausführen:
Neben einer anderen Aktivität:
Sie können die Aufteilung auch seitlich verschieben, sodass die vorherige primäre Aktivität ausgeblendet wird:
eine Aktivität oben starten; Das heißt, im selben Aktivitäten-Stack:
Starten Sie ein vollständiges Fenster mit einer Aktivität in derselben Aufgabe:
Rückwärtsnavigation
Je nach Abhängigkeiten zwischen Aktivitäten oder wie Nutzer das Zurück-Ereignis auslösen, können verschiedene Arten von Anwendungen unterschiedliche Regeln für die Rücknavigation im Splitscreen-Fensterstatus haben, z. B.:
- Zusammenführung: Wenn Aktivitäten einen Bezug haben und einer der Aktivitäten nicht angezeigt werden soll ohne das andere, kann die Rückwärtsnavigation so konfiguriert werden, dass beides abgeschlossen wird.
- Eigenständig: Wenn Aktivitäten vollständig unabhängig sind, wirkt sich die Rücknavigation bei einer Aktivität nicht auf den Status einer anderen Aktivität im Aufgabenfenster aus.
Das Zurück-Ereignis wird an die zuletzt fokussierte Aktivität gesendet, wenn die Navigation über Schaltflächen verwendet wird.
Für die Bedienung über Gesten:
Android 14 (API-Level 34) und niedriger: Das Zurück-Ereignis wird an die Aktivität gesendet, bei der die Geste ausgeführt wurde. Wenn Nutzer von der linken Seite des Bildschirms wischen, wird das Zurück-Ereignis an die Aktivität im linken Bereich des geteilten Fensters gesendet. Wenn Nutzende von der rechten Seite der wird das Zurück-Ereignis an die Aktivität im rechten Fensterbereich gesendet.
Android 15 (API-Level 35) und höher
Wenn Sie mehrere Aktivitäten aus derselben App ausführen, wird mit der Geste unabhängig von der Wischrichtung die oberste Aktivität beendet.
In Szenarien mit zwei Aktivitäten aus verschiedenen Apps (Overlay) wird das Zurück-Ereignis auf die zuletzt im Fokus stehende Aktivität gerichtet, was dem Verhalten der Schaltflächennavigation entspricht.
Layout mit mehreren Ansichten
Mit Jetpack WindowManager können Sie ein Mehrfensterbereich zum Einbetten von Aktivitäten erstellen
Layout auf Geräten mit großen Bildschirmen mit Android 12L (API-Level 32) oder höher und höher
einige Geräte mit älteren Plattformversionen. Vorhandene Apps, die auf mehreren Aktivitäten statt auf Fragmenten oder ansichtenbasierten Layouts wie SlidingPaneLayout
basieren, können die Nutzerfreundlichkeit auf großen Bildschirmen verbessern, ohne den Quellcode umzustrukturieren.
Ein häufiges Beispiel ist die Aufteilung in Listen- und Detailansichten. Um eine qualitativ hochwertige Präsentation zu gewährleisten, startet das System die Listenaktivität und die Anwendung startet dann sofort die Detailaktivität. Das Übergangssystem wartet, bis beide Aktivitäten gezeichnet wurden, und zeigt sie dann zusammen an. Für den Nutzer sind die beiden beginnen, als eine Aktivität zu starten.
Aufgeteilte Attribute
Sie können festlegen, wie das Aufgabenfenster zwischen den aufgeteilten Containern verteilt wird und wie die Container relativ zueinander angeordnet werden.
Legen Sie für Regeln, die in einer XML-Konfigurationsdatei definiert sind, die folgenden Attribute fest:
splitRatio
: Damit werden die Proportionen des Containers festgelegt. Der Wert ist eine Gleitkommazahl im offenen Intervall (0,0, 1,0).splitLayoutDirection
: Gibt an, wie die geteilten Container relativ zueinander angeordnet werden. Zu den Werten gehören:ltr
: von links nach rechtsrtl
: Von rechts nach linkslocale
: Entwederltr
oderrtl
wird anhand der Gebietsschemaeinstellung bestimmt.
Beispiele finden Sie im Abschnitt XML-Konfiguration.
Erstellen Sie für Regeln, die mit den WindowManager APIs erstellt wurden, ein SplitAttributes
-Objekt mit SplitAttributes.Builder
und rufen Sie die folgenden Buildermethoden auf:
setSplitType()
: Legt die Proportionen der aufgeteilten Container fest. Weitere Informationen finden Sie unterSplitAttributes.SplitType
für gültige Argumente, einschließlich derSplitAttributes.SplitType.ratio()
-Methode.setLayoutDirection()
: Legt das Layout der Container fest. Weitere Informationen finden Sie unterSplitAttributes.LayoutDirection
für mögliche Werte.
Beispiele finden Sie im Abschnitt WindowManager API.
Platzhalter
Platzhalteraktivitäten sind leere sekundäre Aktivitäten, die einen Bereich einer Aktivitätsaufteilung. Sie sollen letztendlich durch eine andere Aktivität ersetzt werden, die Inhalte enthält. Beispielsweise könnte eine Platzhalteraktivität die sekundäre Seite einer Aktivität in einem Listendetaillayout belegen, bis ein Element aus der Liste ausgewählt wird. In diesem Fall wird der Platzhalter durch eine Aktivität mit den Detailinformationen für das ausgewählte Listenelement ersetzt.
Standardmäßig zeigt das System Platzhalter nur an, wenn genügend Platz für eine Aktivitätsaufteilung vorhanden ist. Platzhalter werden automatisch fertiggestellt, wenn die Anzeigegröße die Breite oder Höhe zu klein ist, um eine Aufteilung anzuzeigen. Wenn der Platz ausreicht, startet das System den Platzhalter mit einem zurückgesetzten Status neu.
Das stickyPlaceholder
-Attribut einer SplitPlaceholderRule
- oder setSticky()
-Methode von SplitPlaceholder.Builder
kann das Standardverhalten jedoch überschreiben. Wenn für das Attribut oder die Methode der Wert true
angegeben ist, zeigt das System den Platzhalter als oberste Aktivität im Aufgabenfenster an, wenn das Display von einem zweispaltigen zu einem einspaltigen Display minimiert wird (siehe Split-Konfiguration).
Fenstergrößenänderungen
Wenn sich die Gerätekonfiguration ändert und die Breite des Aufgabenfensters so reduziert wird, dass es nicht groß genug für ein mehrspaltiges Layout ist (z. B. wenn ein faltbares Gerät mit großem Bildschirm von der Größe eines Tablets auf die Größe eines Smartphones zusammengefaltet wird oder das App-Fenster im Mehrfenstermodus neu skaliert wird), werden die Aktivitäten, die keine Platzhalter sind, im sekundären Bereich des Aufgabenfensters über den Aktivitäten im primären Bereich gestapelt.
Platzhalteraktivitäten werden nur angezeigt, wenn die Anzeigebreite für eine geteilt. Auf kleineren Bildschirmen wird der Platzhalter automatisch geschlossen. Wenn der Parameter wieder groß genug wird, wird der Platzhalter neu erstellt. Weitere Informationen finden Sie im Abschnitt Platzhalter.
Das Stapeln von Aktivitäten ist möglich, weil die Aktivitäten in WindowManager z-geordnet werden im sekundären Bereich über den Aktivitäten im primären Bereich.
Mehrere Aktivitäten im sekundären Bereich
Aktivität B startet Aktivität C ohne zusätzliche Intent-Flags:
Dies führt zu der folgenden Z-Reihenfolge der Aktivitäten in derselben Aufgabe:
In einem kleineren Aufgabenfenster wird die Anwendung also auf eine einzige Aktivität verkleinert, C ganz oben im Stapel:
Wenn Sie im kleineren Fenster zurücknavigieren, können Sie durch die gestapelten Aktivitäten wechseln übereinander liegen.
Wenn die Konfiguration des Aufgabenfensters auf eine größere Größe wiederhergestellt wird, mehrere Bereiche aufnehmen, werden die Aktivitäten wieder nebeneinander angezeigt.
Gestapelte Aufteilungen
Aktivität B startet Aktivität C zur Seite und verschiebt den Teil zur Seite:
Das Ergebnis ist die folgende Z-Reihenfolge der Aktivitäten in derselben Aufgabe:
In einem kleineren Aufgabenfenster wird die Anwendung auf eine einzelne Aktivität mit C oben reduziert:
Festes Hochformat
Mit der Manifesteinstellung android:screenOrientation können Apps in das Hoch- oder Querformat hochladen. Um die Nutzererfahrung zu verbessern wie Tablets und faltbare Geräte, Gerätehersteller (OEMs) können Anfragen zur Bildschirmausrichtung ignorieren und die App im Hochformat anzeigen lassen. im Querformat oder im Querformat auf Displays im Hochformat.
Wenn die Aktivitäts-Embedding-Funktion aktiviert ist, können OEMs Geräte so anpassen, dass Aktivitäten im Querformat mit Letterbox-Ansicht im Hochformat auf großen Bildschirmen (Breite ≥ 600 dp) angezeigt werden. Wenn bei einer festen Aktivität im Hochformat eine zweite Aktivität gestartet wird, kann das Gerät die beiden Aktivitäten nebeneinander in einem Zweifenster anzeigen.
android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED
immer hinzufügen
an deine App-Manifestdatei an, um Geräte darüber zu informieren, dass deine App
Aktivitätseinbettung (siehe Split-Konfiguration).
Abschnitt). OEM-benutzerdefinierte Geräte können dann entscheiden,
im Hochformat.
Split-Konfiguration
Mit Split-Regeln können Sie Aktivitätsaufteilungen konfigurieren. Sie definieren Aufteilungsregeln in einer XML-Datei Konfigurationsdatei oder mithilfe der Jetpack-WindowManager-API Anrufe.
In beiden Fällen muss Ihre App auf die WindowManager-Bibliothek zugreifen und das System darüber informieren, dass die App die Einbettung von Aktivitäten implementiert hat.
Unternimm Folgendes:
Fügen Sie der Datei
build.gradle
auf Modulebene Ihrer App die neueste Abhängigkeit der WindowManager-Bibliothek hinzu, z. B.:implementation 'androidx.window:window:1.1.0-beta02'
Die WindowManager-Bibliothek stellt alle für die Aktivität erforderlichen Komponenten bereit. und Einbettungen.
Informieren Sie das System darüber, dass Ihre App die Einbettung von Aktivitäten implementiert hat.
Füge das Attribut
android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED
hinzu an <application> des App-Manifests und legen Sie den Parameter Wert auf "true" setzen. Beispiel:<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>
Ab WindowManager-Version 1.1.0-alpha06 werden Aktivitätseinbettungen sind deaktiviert, es sei denn, die Property wird dem Manifest hinzugefügt und auf „true“ gesetzt.
Außerdem können Gerätehersteller die Einstellung nutzen, um benutzerdefinierte Funktionen für Apps, die das Einbetten von Aktivitäten unterstützen Geräte können beispielsweise im Querformat verwenden, um die Aktivitäten für die Wechsel zu einem Zwei-Fenster-Layout, wenn eine zweite Aktivität beginnt (siehe Festes Hochformat).
XML-Konfiguration
So erstellst du eine XML-basierte Implementierung der Aktivitäts-Embedding-Funktion:
Erstellen Sie eine XML-Ressourcendatei, die folgende Aufgaben erfüllt:
- Definiert Aktivitäten, die eine Aufteilung teilen
- Konfiguriert die Optionen für die Aufteilung
- Erstellt einen Platzhalter für den sekundären Container der Aufteilung, wenn keine Inhalte verfügbar sind.
- Gibt Aktivitäten an, die niemals Teil einer Aufteilung sein sollten
Beispiel:
<!-- 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>
Erstellen Sie einen Initialisierer.
Die Komponente „WindowManager“
RuleController
analysiert die XML-Konfigurationsdatei und stellt die Regeln dem System zur Verfügung. Eine Jetpack-Start-BibliothekInitializer
stellt die XML-Datei beim Starten der App fürRuleController
zur Verfügung, damit die Regeln beim Starten von Aktivitäten in Kraft treten.So erstellen Sie einen Initiierer:
Fügen Sie die neueste Abhängigkeit der Jetpack Startup-Bibliothek zu Ihrer Modulebene hinzu.
build.gradle
-Datei. Beispiel:implementation 'androidx.startup:startup-runtime:1.1.1'
Erstellen Sie eine Klasse, die die
Initializer
-Schnittstelle implementiert.Der Initialisierer stellt die Split-Regeln für
RuleController
bereit, indem er die ID der XML-Konfigurationsdatei (main_split_config.xml
) an dieRuleController.parseRules()
-Methode übergibt.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(); } }
Erstellen Sie einen Contentanbieter für die Regeldefinitionen.
androidx.startup.InitializationProvider
der App-Manifestdatei hinzufügen als<provider>
. Geben Sie einen Verweis auf die Implementierung IhrerRuleController
-Initialisierer,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
erkennt und initialisiertSplitInitializer
vor dem wird die MethodeonCreate()
der App aufgerufen. Daher befinden sich die Aufteilungsregeln wenn die Hauptaktivität der App beginnt.
WindowManager API
Sie können das Einbetten von Aktivitäten mit wenigen API-Aufrufen programmgesteuert implementieren. Führen Sie die Aufrufe in der onCreate()
-Methode einer Unterklasse von Application
aus, damit die Regeln in Kraft sind, bevor Aktivitäten gestartet werden.
So erstellen Sie programmatisch eine Aktivitätsaufteilung:
So erstellen Sie eine Split-Regel:
SplitPairFilter
erstellen der die Aktivitäten identifiziert, die sich der Aufteilung teilen: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 );
Fügen Sie den Filter einem Filtersatz hinzu:
Kotlin
val filterSet = setOf(splitPairFilter)
Java
Set<SplitPairFilter> filterSet = new HashSet<>(); filterSet.add(splitPairFilter);
Erstellen Sie Layoutattribute für die Aufteilung:
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();
Mit
SplitAttributes.Builder
wird ein Objekt mit Layoutattributen erstellt:setSplitType()
: Hiermit wird festgelegt, wie der verfügbare Anzeigebereich den einzelnen Aktivitätscontainern zugewiesen wird. Der Verhältnisaufteilungstyp gibt den Anteil des verfügbaren Display-Bereichs, der dem Primärcontainer; belegt der sekundäre Container den Rest den verfügbaren Anzeigebereich.setLayoutDirection()
: Gibt an, wie die Aktivitätscontainer relativ zueinander angeordnet werden, zuerst der primäre Container.
SplitPairRule
erstellen: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
erstellt und konfiguriert die Regel:filterSet
: enthält Split-Pair-Filter, die bestimmen, wann die Regel anwenden, indem Aktivitäten identifiziert werden, die eine Aufteilung aufweisen.setDefaultSplitAttributes()
: Wendet Layoutattribute auf die Regel.setMinWidthDp()
: Hiermit wird die minimale Anzeigebreite festgelegt (in dichteunabhängige Pixel, dp), die eine Aufteilung ermöglichen.setMinSmallestWidthDp()
: Legt den Mindestwert (in dp) fest, den die kleinere der beiden Displayabmessungen haben muss, um unabhängig von der Geräteausrichtung eine Aufteilung zu ermöglichen.setMaxAspectRatioInPortrait()
: Hiermit wird das maximale Seitenverhältnis (Höhe:Breite) für die Hochformatanzeige festgelegt, bei der Aktivitätsaufschlüsselungen angezeigt werden. Wenn das Seitenverhältnis eines Hochformat-Displays das maximale Seitenverhältnis überschreitet, werden Splitscreens unabhängig von der Breite des Displays deaktiviert. Hinweis: Der Standardwert ist 1,4. Das bedeutet, dass Aktivitäten auf den meisten Tablets im Hochformat das gesamte Aufgabenfenster einnehmen. Siehe auchSPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT
undsetMaxAspectRatioInLandscape()
Der Standardwert für Querformat istALWAYS_ALLOW
.setFinishPrimaryWithSecondary()
: Legt fest, wie fertig sind. die Aktivitäten im sekundären Container auf die Aktivitäten im primären Container.NEVER
gibt an, dass das System die primären Aktivitäten nicht beenden soll, wenn alle Aktivitäten im sekundären Container abgeschlossen sind (siehe Aktivitäten beenden).setFinishSecondaryWithPrimary()
: Hiermit wird festgelegt, wie sich das Beenden aller Aktivitäten im primären Container auf die Aktivitäten im sekundären Container auswirkt.ALWAYS
gibt an, dass das System immer Schließen Sie die Aktivitäten im sekundären Container ab, wenn alle Aktivitäten in der Ausführung des primären Containers (siehe Aktivitäten beenden) ausführen.setClearTop()
: Gibt an, ob alle Aktivitäten im sekundäre Container abgeschlossen sind, wenn eine neue Aktivität in Container. Einfalse
-Wert gibt an, dass neue Aktivitäten über den Aktivitäten, die sich bereits im sekundären Container befinden.
Rufen Sie die Singleton-Instanz von WindowManager
RuleController
ab, und füge die folgende Regel hinzu:Kotlin
val ruleController = RuleController.getInstance(this) ruleController.addRule(splitPairRule)
Java
RuleController ruleController = RuleController.getInstance(this); ruleController.addRule(splitPairRule);
Erstelle einen Platzhalter für den sekundären Container, wenn Inhalte nicht verfügbar sind:
Erstelle ein
ActivityFilter
-Element, das die Aktivität identifiziert, mit der Der Platzhalter teilt eine Aufteilung des Aufgabenfensters mit:Kotlin
val placeholderActivityFilter = ActivityFilter( ComponentName(this, ListActivity::class.java), null )
Java
ActivityFilter placeholderActivityFilter = new ActivityFilter( new ComponentName(this, ListActivity.class), null );
Fügen Sie den Filter einem Filtersatz hinzu:
Kotlin
val placeholderActivityFilterSet = setOf(placeholderActivityFilter)
Java
Set<ActivityFilter> placeholderActivityFilterSet = new HashSet<>(); placeholderActivityFilterSet.add(placeholderActivityFilter);
Erstellen:
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
erstellt und konfiguriert die Regel:placeholderActivityFilterSet
: Enthält Aktivitätsfilter, mit denen festgelegt wird, wann die Regel angewendet werden soll. Dazu werden Aktivitäten angegeben, mit denen die Platzhalteraktivität verknüpft ist.Intent
: Gibt den Start der Platzhalteraktivität an.setDefaultSplitAttributes()
: Wendet Layoutattribute auf die Regel an.setMinWidthDp()
: Mit dieser Einstellung wird die Mindestbreite des Displays (in dichteunabhängigen Pixeln, dp) festgelegt, ab der eine Aufteilung möglich ist.setMinSmallestWidthDp()
: Legt den Mindestwert (in dp) fest, mit dem der kleinere der beiden angezeigt wird Die Abmessungen müssen unabhängig vom Gerät eine Aufteilung ermöglichen Ausrichtung.setMaxAspectRatioInPortrait()
: Mit diesem Attribut wird das maximale Seitenverhältnis (Höhe:Breite) für die Hochformatanzeige festgelegt, bei der Aktivitätsaufschlüsselungen angezeigt werden. Hinweis: Das Der Standardwert ist 1,4, was dazu führt, dass Aktivitäten die Aufgabe ausführen. auf den meisten Tablets im Hochformat. Siehe auchSPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT
undsetMaxAspectRatioInLandscape()
Der Standardwert für das Querformat istALWAYS_ALLOW
.setFinishPrimaryWithPlaceholder()
: Legt fest, wie sich das Beenden der Platzhalteraktivität auf die Aktivitäten auswirkt im primären Container. „IMMER“ gibt an, dass das System die Aktivitäten im primären Container immer beenden soll, wenn der Platzhalter abgeschlossen ist (siehe Aktivitäten beenden).setSticky()
: Hiermit wird festgelegt, ob die Platzhalteraktivität wird auf kleinen Displays oben im Aktivitätsstapel angezeigt, sobald das Symbol Platzhalter wurde zuerst in einer Aufteilung mit ausreichender Mindestzahl angezeigt Breite.
Fügen Sie die Regel dem WindowManager
RuleController
hinzu:Kotlin
ruleController.addRule(splitPlaceholderRule)
Java
ruleController.addRule(splitPlaceholderRule);
Geben Sie Aktivitäten an, die niemals Teil einer Aufteilung sein sollten:
Erstellen Sie eine
ActivityFilter
, die eine Aktivität identifiziert, die immer den gesamten Bereich für die Aufgabenanzeige einnehmen soll:Kotlin
val expandedActivityFilter = ActivityFilter( ComponentName(this, ExpandedActivity::class.java), null )
Java
ActivityFilter expandedActivityFilter = new ActivityFilter( new ComponentName(this, ExpandedActivity.class), null );
Fügen Sie den Filter einem Filtersatz hinzu:
Kotlin
val expandedActivityFilterSet = setOf(expandedActivityFilter)
Java
Set<ActivityFilter> expandedActivityFilterSet = new HashSet<>(); expandedActivityFilterSet.add(expandedActivityFilter);
ActivityRule
erstellen:Kotlin
val activityRule = ActivityRule.Builder(expandedActivityFilterSet) .setAlwaysExpand(true) .build()
Java
ActivityRule activityRule = new ActivityRule.Builder( expandedActivityFilterSet ).setAlwaysExpand(true) .build();
ActivityRule.Builder
erstellt und konfiguriert die Regel:expandedActivityFilterSet
: Enthält Aktivitätsfilter, mit denen Sie festlegen, wann die Regel angewendet werden soll. Dazu werden Aktivitäten angegeben, die von der Aufteilung ausgeschlossen werden sollen.setAlwaysExpand()
: Gibt an, ob die Aktivität das gesamte Aufgabenfenster aus.
Fügen Sie die Regel dem WindowManager
RuleController
hinzu:Kotlin
ruleController.addRule(activityRule)
Java
ruleController.addRule(activityRule);
Anwendungsübergreifende Einbettung
Unter Android 13 (API-Level 33) und höher können Apps Aktivitäten von anderen Apps. Anwendungsübergreifende oder übergreifende UID, Einbettung von Aktivitäten ermöglicht die visuelle Integration von Aktivitäten aus verschiedenen Android-Apps. Die eine Aktivität der Host-App und eine eingebettete Aktivität eine andere App auf dem Bildschirm nebeneinander oder oben und unten auf dem Bildschirm Aktivitätseinbettung.
So könnte die Einstellungen-App beispielsweise die Aktivität der Hintergrundauswahl aus der App „WallpaperPicker“ einbetten:
Vertrauensmodell
Hostprozesse, die Aktivitäten aus anderen Apps einbetten, können die Darstellung der eingebetteten Aktivitäten, einschließlich Größe, Position, Zuschneiden und Transparenz. Böswillige Hosts können diese Funktion nutzen, um Nutzer zu täuschen und Clickjacking oder andere Angriffe auf die Benutzeroberfläche durchzuführen.
Damit der Missbrauch eingebetteter App-Aktivitäten verhindert wird, müssen Apps bei Android diese Option aktivieren um die Einbettung ihrer Aktivitäten zu ermöglichen. Apps können Hosts als vertrauenswürdig oder nicht vertrauenswürdig kennzeichnen.
Vertrauenswürdige Hosts
Um es anderen Anwendungen zu ermöglichen, die Darstellung von
Aktivitäten aus deiner App zu entfernen, gib das SHA-256-Zertifikat des Hosts an
im Attribut android:knownActivityEmbeddingCerts
des
<activity>
- oder <application>
-Elemente der Manifestdatei deiner App.
Legen Sie den Wert von android:knownActivityEmbeddingCerts
entweder als String fest:
<activity
android:name=".MyEmbeddableActivity"
android:knownActivityEmbeddingCerts="@string/known_host_certificate_digest"
... />
oder, um mehrere Zertifikate anzugeben, ein String-Array:
<activity
android:name=".MyEmbeddableActivity"
android:knownActivityEmbeddingCerts="@array/known_host_certificate_digests"
... />
der auf eine Ressource wie die folgende verweist:
<resources>
<string-array name="known_host_certificate_digests">
<item>cert1</item>
<item>cert2</item>
...
</string-array>
</resources>
App-Inhaber können Gradle ausführen, um einen SHA-Zertifikat-Digest zu erhalten.
signingReport
Aufgabe. Der Zertifikats-Digest ist der SHA-256-Fingerabdruck ohne die Trennpunkte. Weitere Informationen finden Sie unter Bericht zur Signatur ausführen und Client authentifizieren.
Nicht vertrauenswürdige Hosts
Wenn Sie zulassen möchten, dass andere Apps die Aktivitäten Ihrer App einbetten und deren Darstellung steuern können, geben Sie das Attribut android:allowUntrustedActivityEmbedding
in den Elementen <activity>
oder <application>
im App-Manifest an. Beispiel:
<activity
android:name=".MyEmbeddableActivity"
android:allowUntrustedActivityEmbedding="true"
... />
Der Standardwert des Attributs ist „false“, wodurch App-übergreifende Aktivitäten verhindert werden. und Einbettungen.
Benutzerdefinierte Authentifizierung
Um die Risiken von nicht vertrauenswürdigen eingebetteten Aktivitäten zu minimieren, erstellen Sie einen benutzerdefinierten Authentifizierungsmechanismus, der die Identität des Hosts überprüft. Wenn Sie die Hostzertifikate kennen, verwenden Sie die androidx.security.app.authenticator
-Bibliothek, um sich zu authentifizieren. Wenn sich der Host nach dem Einbetten Ihrer Aktivität authentifiziert, können Sie die tatsächlichen Inhalte anzeigen. Falls nicht, können Sie die Nutzenden darüber informieren,
und den Inhalt blockieren.
Mit der Methode ActivityEmbeddingController#isActivityEmbedded()
aus der Jetpack WindowManager-Bibliothek kannst du prüfen, ob ein Host deine Aktivität einbettet, z. B. so:
Kotlin
fun isActivityEmbedded(activity: Activity): Boolean { return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity) }
Java
boolean isActivityEmbedded(Activity activity) { return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity); }
Mindestgröße
Das Android-System wendet die im App-Manifest-Element <layout>
angegebene minimale Höhe und Breite auf eingebettete Aktivitäten an. Wenn für eine Anwendung keine Mindesthöhe und ‑breite angegeben ist, gelten die Standardwerte des Systems (sw220dp
).
Wenn der Host versucht, die Größe des eingebetteten Containers auf eine Größe kleiner als das Minimum zu ändern, wird der eingebettete Container so erweitert, dass er die gesamten Aufgabengrenzen einnimmt.
<Aktivitätsalias>
Damit das Einbetten vertrauenswürdiger oder nicht vertrauenswürdiger Aktivitäten mit dem Element <activity-alias>
funktioniert, muss android:knownActivityEmbeddingCerts
oder android:allowUntrustedActivityEmbedding
auf die Zielaktivität und nicht auf den Alias angewendet werden. Die Richtlinie, die die Sicherheit des Systemservers überprüft, ist
basierend auf den Flags, die für das Ziel festgelegt sind, und nicht
auf dem Alias.
Hostanwendung
Hostanwendungen implementieren das Einbetten von App-übergreifenden Aktivitäten auf die gleiche Weise wie das Einbetten von Aktivitäten in einer einzelnen App. Mit den Objekten SplitPairRule
und SplitPairFilter
oder ActivityRule
und ActivityFilter
werden eingebettete Aktivitäten und Aufgabenfensteraufteilungen angegeben. Split-Regeln werden statisch in XML oder zur Laufzeit mithilfe von Jetpack WindowManager API-Aufrufen definiert.
Wenn eine Host-Anwendung versucht, eine Aktivität einzubetten, für die sie App-übergreifende Einbettung nimmt die Aktivität die gesamten Aufgabengrenzen ein. Daher müssen Hostanwendungen wissen, ob das Einbetten in andere Apps für die Zielaktivitäten zulässig ist.
Wenn eine eingebettete Aktivität eine neue Aktivität in derselben Aufgabe startet und die neue App-übergreifende Einbettung wird nicht aktiviert, die Aktivität innerhalb der Aufgabengrenzen, anstatt die Aktivität im eingebetteten Container zu überlagern.
Eine Host-Anwendung kann ihre eigenen Aktivitäten uneingeschränkt einbetten, wenn die Aktivitäten in derselben Aufgabe starten.
Beispiele für Split-Tests
Vom ganzen Fenster teilen
Kein Refactoring erforderlich. Sie können die Konfiguration für die Aufteilung statisch oder zur Laufzeit definieren und dann Context#startActivity()
ohne zusätzliche Parameter aufrufen.
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Standardmäßig aufteilen
Wenn die Landingpage einer App in zwei Teile geteilt werden soll Container auf großen Bildschirmen verwenden, ist die User Experience am besten, wenn beide Aktivitäten gleichzeitig erstellt und präsentiert werden. Inhalte sind für den sekundären Container der Aufteilung jedoch möglicherweise erst verfügbar, wenn der Nutzer mit der Aktivität im primären Container interagiert, z. B. ein Element aus einem Navigationsmenü auswählt. Eine Platzhalteraktivität kann die Lücke füllen, bis Inhalte im sekundären Container der Aufteilung angezeigt werden können (siehe Abschnitt Platzhalter).
Wenn Sie eine Aufteilung mit einem Platzhalter erstellen möchten, erstellen Sie einen Platzhalter und verknüpfen Sie ihn mit der primären Aktivität:
<SplitPlaceholderRule
window:placeholderActivityName=".PlaceholderActivity">
<ActivityFilter
window:activityName=".MainActivity"/>
</SplitPlaceholderRule>
Deeplink-Aufteilung
Wenn eine App einen Intent empfängt, kann die Zielaktivität als sekundärer Teil einer Aktivitätsaufteilung; z. B. eine Anfrage, ein Detail anzuzeigen, mit Informationen zu einem Element aus einer Liste. Auf kleinen Displays sind die Details wird im vollständigen Aufgabenfenster angezeigt. auf größeren Geräten neben der Liste.
Die Startanfrage sollte an die Hauptaktivität und die Zieldetails weitergeleitet werden. sollte in einem Split gestartet werden. Das System wählt automatisch die richtige Präsentation – gestapelt oder nebeneinander – basierend auf den verfügbaren Anzeigebreite.
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)); }
Das Deeplink-Ziel ist möglicherweise die einzige Aktivität, die für die Nutzenden im Rückwärts-Navigationsstapel sind, und Sie sollten vermeiden, die Detailaktivität und lassen Sie nur die Hauptaktivität:
Stattdessen können Sie beide Aktivitäten gleichzeitig abschließen, indem Sie das Attribut finishPrimaryWithSecondary
verwenden:
<SplitPairRule
window:finishPrimaryWithSecondary="always">
<SplitPairFilter
window:primaryActivityName=".ListActivity"
window:secondaryActivityName=".DetailActivity"/>
</SplitPairRule>
Weitere Informationen finden Sie im Abschnitt Konfigurationsattribute.
Mehrere Aktivitäten in aufgeteilten Containern
Durch das Stapeln mehrerer Aktivitäten in einem geteilten Container können Nutzer tief Inhalte. Bei einer Aufteilung in Listen- und Detailansicht muss der Nutzer beispielsweise möglicherweise einen untergeordneten Detailbereich aufrufen, die Hauptaktivität aber beibehalten:
Kotlin
class DetailActivity { . . . fun onOpenSubDetail() { startActivity(Intent(this, SubDetailActivity::class.java)) } }
Java
public class DetailActivity { . . . void onOpenSubDetail() { startActivity(new Intent(this, SubDetailActivity.class)); } }
Die Unterdetailaktivität wird über der Detailaktivität platziert und blendet sie aus:
Der Nutzer kann dann zur vorherigen Detailebene zurückkehren, über den Stack:
Das Stapeln von Aktivitäten übereinander ist das Standardverhalten, wenn Aktivitäten über eine Aktivität im selben sekundären Container gestartet werden. Aktivitäten die aus dem primären Container in einem aktiven Split gestartet werden, sekundärer Container oben im Aktivitätsstapel.
Aktivitäten in einer neuen Aufgabe
Wenn Aktivitäten in einem geteilten Aufgabenfenster Aktivitäten in einer neuen Aufgabe starten, ist die neue Aufgabe unabhängig von der Aufgabe, die die Aufteilung enthält, und wird im Vollfenster angezeigt. Auf dem Bildschirm „Letzte“ werden zwei Aufgaben angezeigt: die Aufgabe in der Aufteilung und die neue Aufgabe.
Aktivität ersetzen
Aktivitäten können im sekundären Container-Stack ersetzt werden, z. B. wenn die primäre Aktivität für die Navigation auf oberster Ebene verwendet wird und die sekundäre Aktivität ein ausgewähltes Ziel ist. Jede Auswahl aus der Navigation auf oberster Ebene sollte eine neue Aktivität im sekundären Container starten und die vorherigen Aktivitäten entfernen.
Wenn die App die Aktivität nicht im sekundären Container beendet, wenn der Änderungen an der Navigationsauswahl, könnte die Rückwärtsnavigation verwirrend sein, im zusammengeklappten Zustand minimiert ist. Wenn Sie z. B. ein Menü in der primären Bereich und die Bildschirme A und B im sekundären Bereich gestapelt, klappt das Smartphone zusammen, B befindet sich auf A und A befindet sich über dem Menü. Wenn der Nutzer von B zurückgeht, wird anstelle des Menüs A angezeigt.
In solchen Fällen muss Bildschirm A aus dem Backstack entfernt werden.
Standardmäßig werden beim Starten in einem neuen Container über einer vorhandenen Spaltung die neuen sekundären Container oben platziert und die alten im Hintergrundstapel beibehalten. Sie können die Aufteilungen so konfigurieren, dass die vorherigen sekundären Container mit clearTop
gelöscht und neue Aktivitäten normal gestartet werden.
<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))); } }
Alternativ können Sie dieselbe sekundäre Aktivität verwenden und von der primären (Menü-)Aktivität neue Intents senden, die auf dieselbe Instanz verweisen, aber einen Status- oder UI-Update im sekundären Container auslösen.
Mehrere Aufteilungen
Apps können eine mehrstufige Tiefennavigation bieten, indem zusätzliche Aktivitäten gestartet werden beiseite.
Startet eine Aktivität in einem sekundären Container eine neue Aktivität neben der Seite, wird eine neue Aufteilung über die vorhandene Aufteilung erstellt.
Der Backstack enthält alle zuvor geöffneten Aktivitäten, sodass Nutzer nach Abschluss von C zur A/B-Testverzweigung wechseln können.
Um eine neue Aufteilung zu erstellen, starten Sie die neue Aktivität neben der bestehenden sekundärer Container. Deklarieren Sie die Konfigurationen sowohl für die A/B- als auch für die B/C-Aufteilung und starten Sie Aktivität C wie gewohnt über 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)); } }
Auf Statusänderungen reagieren
Verschiedene Aktivitäten in einer App können UI-Elemente haben, die dieselbe Funktion haben Funktion; z. B. ein Steuerelement, das ein Fenster mit Einstellungen.
Wenn zwei Aktivitäten, die ein UI-Element gemeinsam haben, sich in einem Split befinden, ist es und es möglicherweise verwirrend ist, das Element in beiden Aktivitäten anzuzeigen.
Wenn Sie wissen möchten, wann sich Aktivitäten in einem Split befinden, prüfen Sie den Fluss SplitController.splitInfoList
oder registrieren Sie einen Listener mit SplitControllerCallbackAdapter
für Änderungen am Split-Status. Passen Sie dann die Benutzeroberfläche entsprechend an:
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); }); }
Coroutinen können in jedem Lebenszyklusstatus gestartet werden, werden aber in der Regel im Status STARTED
gestartet, um Ressourcen zu sparen. Weitere Informationen finden Sie unter Kotlin-Coroutinen mit lebenszyklusbewussten Komponenten verwenden.
Callbacks können in jedem Lebenszyklusstatus erfolgen, auch wenn eine Aktivität
angehalten. Hörer sollten in der Regel in onStart()
registriert und in onStop()
nicht registriert sein.
Modales Fenster im Vollbildmodus
Bei einigen Aktivitäten können Nutzer erst dann mit der Anwendung interagieren, wenn eine bestimmte Aktion ausgeführt wurde, z. B. eine Aktivität auf dem Anmeldebildschirm, ein Bildschirm zur Bestätigung der Richtlinien oder eine Fehlermeldung. Modale Aktivitäten sollten nicht in einem Split angezeigt werden.
Sie können erzwingen, dass eine Aktivität immer das Aufgabenfenster ausfüllt, indem Sie die Schaltfläche zum Maximieren verwenden Konfiguration:
<ActivityRule
window:alwaysExpand="true">
<ActivityFilter
window:activityName=".FullWidthActivity"/>
</ActivityRule>
Aktivitäten abschließen
Nutzer können Aktivitäten auf beiden Seiten des geteilten Bereichs beenden, indem sie vom Rand wischen. des Bildschirms:
Wenn das Gerät so eingerichtet ist, dass die Schaltfläche „Zurück“ anstelle der Bedienung über Gesten verwendet wird, wird die Eingabe an die fokussierte Aktivität gesendet, d. h. die Aktivität, die berührt oder zuletzt eingeführt.
Der Effekt, dass das Beenden aller Aktivitäten in einem Container auf die jeweils andere Seite wirkt hängt von der Split-Konfiguration ab.
Konfigurationsattribute
Sie können Regelattribute für Aufteilungspaare angeben, um zu konfigurieren, wie das Fertigstellen die Aktivitäten auf der einen Seite der Teilung sich auf die Aktivitäten auf der anderen Seite der der Spaltung. Die Attribute sind:
window:finishPrimaryWithSecondary
– Wie sich das Abschließen aller Aktivitäten im sekundären Container auf die Aktivitäten im primären Container auswirktwindow:finishSecondaryWithPrimary
– Abschluss aller Aktivitäten in Der primäre Container wirkt sich auf die Aktivitäten im sekundären Container aus.
Mögliche Werte der Attribute:
always
: Die Aktivitäten im zugehörigen Container werden immer beendet.never
: Die Aktivitäten im zugehörigen Container werden nie beendet.adjacent
: Die Aktivitäten im zugehörigen Container werden beendet, wenn werden die beiden Container nebeneinander angezeigt, aber nicht, wenn der Zwei Behälter sind gestapelt
Beispiel:
<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>
Standardkonfiguration
Wenn alle Aktivitäten in einem Container eines Splits abgeschlossen sind, wird der verbleibende Container das gesamte Fenster ausfüllt:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Aktivitäten gemeinsam beenden
Aktivitäten im primären Container automatisch beenden, wenn alle Aktivitäten im sekundären Container abgeschlossen sind:
<SplitPairRule
window:finishPrimaryWithSecondary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Schließen Sie die Aktivitäten automatisch im sekundären Container ab, wenn alle Aktivitäten im primären Container wurden beendet:
<SplitPairRule
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Schließen Sie Aktivitäten gemeinsam ab, wenn alle Aktivitäten in der primären oder Abschluss des sekundären Containers:
<SplitPairRule
window:finishPrimaryWithSecondary="always"
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Mehrere Aktivitäten in Containern abschließen
Wenn mehrere Aktivitäten in einem geteilten Container gestapelt sind, wird eine Aktivität beendet unten im Stapel beenden Aktivitäten nicht automatisch oben.
Wenn sich beispielsweise zwei Aktivitäten im sekundären Container befinden, C über B:
Die Konfiguration der Aufteilung wird durch die Konfiguration der Aktivitäten A und B definiert:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Beim Abschließen der obersten Aktivität wird die Aufteilung beibehalten.
Durch das Abschließen der unteren (Stamm-)Aktivität des sekundären Containers wird das Element nicht entfernt. die darauf aufbauenden Aktivitäten; und behält so auch die Aufteilung bei.
Alle zusätzlichen Regeln für das gemeinsame Abschließen von Aktivitäten, z. B. das Abschließen der sekundären Aktivität mit der primären, werden ebenfalls ausgeführt:
<SplitPairRule
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Und wenn die Aufteilung so konfiguriert ist, dass die primäre und die sekundäre Instanz zusammen abgeschlossen werden:
<SplitPairRule
window:finishPrimaryWithSecondary="always"
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Aufteilungsattribute während der Laufzeit ändern
Die Eigenschaften einer aktiven und sichtbaren Aufteilung können nicht geändert werden. Ändern der wirken sich Aufteilungsregeln auf zusätzliche Aktivitäten und neue Container aus, aber nicht vorhandene und aktive Aufteilungen.
Um die Eigenschaften aktiver Aufteilungen zu ändern, schließen Sie die Nebenaktivität ab oder und dann mit einer neuen Konfiguration wieder an der Seite starten.
Eigenschaften mit dynamischer Aufteilung
Android 15 (API-Level 35) und höher, unterstützt von Jetpack WindowManager 1.4 und höher, bieten dynamische Funktionen, mit denen sich die Aufteilung von eingebetteten Aktivitäten konfigurieren lässt. Dazu gehören:
- Bereichserweiterung: Mit einem interaktiven, verschiebbaren Trennstrich können Nutzer die Bereiche in einer geteilten Präsentation anpassen.
- Anpinnen von Aktivitäten:Nutzer können Inhalte in einem Container anpinnen und Isolieren Sie die Navigation im Container von der Navigation im anderen Container.
- Abdunkeln von Vollbilddialogfeldern: Beim Einblenden eines Dialogfelds können Apps angeben, ob das gesamte Aufgabenfenster oder nur der Container abgedunkelt werden soll, über den das Dialogfeld geöffnet wurde.
Bereich maximieren
Mit der Ansichtserweiterung können Nutzer die Bildschirmfläche anpassen, die den beiden Aktivitäten in einem Layout mit zwei Ansichten zugewiesen ist.
So passen Sie das Aussehen des Fensterteilers an und legen den Bereich fest, in dem er verschoben werden kann:
Instanz von
DividerAttributes
erstellenPassen Sie die Trennlinienattribute an:
color
:Die Farbe des ziehbaren Bereichstrennzeichens.widthDp
:Breite des ziehbaren Bereichstrennzeichens. Festlegen aufWIDTH_SYSTEM_DEFAULT
, damit die Trennlinie vom System bestimmt werden kann Breite.Ziehbereich:Dies ist der minimale Prozentsatz des Bildschirms, der in beiden Bereichen angezeigt werden kann. besetzt sind. Kann zwischen 0,33 und 0,66 liegen. Festlegen auf
DRAG_RANGE_SYSTEM_DEFAULT
, damit das System den Ziehpunkt bestimmen kann Bereich.
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();
Anpinnen von Aktivitäten
Mit der Aktivitäts-Anpinning-Funktion können Nutzer eines der geteilten Fenster anpinnen, damit die Aktivität unverändert bleibt, während sie im anderen Fenster navigieren. Aktivität Anpinnen bietet ein verbessertes Multitasking.
So aktivieren Sie die Funktion zum Anpinnen von Aktivitäten in Ihrer App:
Fügen Sie der Layoutdatei der Aktivität, die Sie anpinnen möchten, eine Schaltfläche hinzu, z. B. die Detailaktivität eines Listendetaillayouts:
<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>
Legen Sie in der
onCreate()
-Methode der Aktivität einen "onclick"-Listener auf der Schaltfläche: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); });
Vollbild dimmen
Bei Aktivitäten werden die Displays in der Regel gedimmt, um die Aufmerksamkeit auf einen Dialog zu lenken. In sollten beide Bereiche des zweiteiligen Bildschirms gedimmt werden, nur den Bereich mit der Aktivität, mit der das Dialogfeld geöffnet wurde, für eine einheitliche Benutzeroberfläche Nutzererfahrung.
Bei WindowManager 1.4 und höher wird das gesamte App-Fenster standardmäßig gedimmt, wenn ein
wird geöffnet (siehe EmbeddingConfiguration.DimAreaBehavior.ON_TASK
).
Wenn Sie nur den Container der Aktivität dimmen möchten, durch die das Dialogfeld geöffnet wurde, verwenden Sie EmbeddingConfiguration.DimAreaBehavior.ON_ACTIVITY_STACK
.
Aktivität aus einem geteilten Fenster in ein Vollbildfenster extrahieren
Erstellen Sie eine neue Konfiguration, die das vollständige Fenster der Nebenaktivität anzeigt, und Starten Sie die Aktivität mit einem Intent neu, der in dieselbe Instanz aufgelöst wird.
Unterstützung von Aufteilungen während der Laufzeit prüfen
Die Einbettung von Aktivitäten wird unter Android 12L (API-Level 32) und höher unterstützt, ist aber auch auf einigen Geräten mit älteren Plattformversionen verfügbar. Wenn Sie die Verfügbarkeit der Funktion zur Laufzeit prüfen möchten, verwenden Sie das Attribut SplitController.splitSupportStatus
oder die Methode 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. }
Wenn Aufteilungen nicht unterstützt werden, werden Aktivitäten über dem Aktivitätsstapel gestartet (gemäß dem Modell für das Einbetten von Inhalten ohne Aktivität).
Systemüberschreibung verhindern
Die Hersteller von Android-Geräten (Erstausrüster, OEMs) können die Einbettung von Aktivitäten als Funktion des Gerätesystems implementieren. Die gibt das System Aufteilungsregeln für Apps mit mehreren Aktivitäten an, wodurch das Windowing überschrieben wird. Verhalten der Apps. Durch die Systemüberschreibung werden Apps mit mehreren Aktivitäten in einen systemdefinierten Aktivitäts-Embedding-Modus gezwungen.
Die Einbettung von Systemaktivitäten kann die App-Darstellung durch mehrspaltige Layouts wie Liste-Detail verbessern, ohne dass Änderungen an der App vorgenommen werden müssen. Die Einbettung von Systemaktivitäten kann jedoch auch zu falschen App-Layouts, Fehlern oder Konflikten mit der von der App implementierten Einbettung von Aktivitäten führen.
Ihre App kann das Einbetten von Systemaktivitäten verhindern oder zulassen, indem Sie eine Property in der Manifestdatei der App festlegen, z. B.:
<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>
Der Property-Name wird in Jetpack WindowManager WindowProperties
definiert.
-Objekt enthält. Setzen Sie den Wert auf false
, wenn in Ihrer App Aktivitätseinbettungen implementiert sind.
Wenn Sie anderweitig verhindern möchten, dass das System seine Aktivitätseinbettung anwendet
Regeln für Ihre App. Legen Sie den Wert auf true
fest, damit das System diese anwenden kann
systemdefinierten Aktivitäten
in deine App einzubetten.
Einschränkungen und Vorbehalte
- Nur die Host-App der Aufgabe, die als Inhaber der Stammaktivität in der Aufgabe angegeben ist, kann andere Aktivitäten in der Aufgabe organisieren und einbetten. Wenn Aktivitäten, die das Einbetten und Aufteilen unterstützen, in einer Aufgabe ausgeführt werden, die zu einer anderen Anwendung gehört, funktionieren das Einbetten und Aufteilen für diese Aktivitäten nicht.
- Aktivitäten können nur innerhalb einer einzelnen Aufgabe organisiert werden. Aktivität starten in einer neuen Aufgabe immer in einem neuen maximierten Fenster bereits vorhandenen Aufteilungen.
- Nur Aktivitäten im selben Prozess können organisiert und aufgeteilt werden. Der
SplitInfo
-Callback meldet nur Aktivitäten, die zum selben Prozess gehören, da keine Informationen zu Aktivitäten in anderen Prozessen verfügbar sind. - Jede Paar- oder einzelne Aktivitätsregel gilt nur für Aktivitätsstarts, die nachdem die Regel registriert wurde. Es gibt derzeit keine Möglichkeit, vorhandene Aufteilungen oder ihre visuellen Eigenschaften zu aktualisieren.
- Die Filterkonfiguration für das Split-Pair-Tracking muss mit den Intents übereinstimmen, die beim vollständigen Starten von Aktivitäten verwendet werden. Der Abgleich erfolgt an dem Punkt, an dem ein neuer die Aktivität während des Bewerbungsprozesses gestartet wird, Komponentennamen, die später im Systemprozess aufgelöst werden, impliziten Intents. Wenn der Name einer Komponente zum Zeitpunkt der Einführung nicht bekannt ist, kann stattdessen ein Platzhalter („*/*“) verwendet und die Filterung basierend auf der Intent-Aktion durchgeführt werden.
- Es ist derzeit nicht möglich, Aktivitäten nach der Erstellung zwischen Containern oder zwischen Aufteilungen zu verschieben. Teilungen werden von der WindowManager-Bibliothek nur erstellt, wenn neue Aktivitäten mit übereinstimmenden Regeln gestartet werden. Sie werden wieder gelöscht, wenn die letzte Aktivität in einem Teilcontainer beendet ist.
- Aktivitäten können neu gestartet werden, wenn sich die Konfiguration ändert. erstellt oder entfernt wird und sich die Aktivitätsgrenzen ändern, kann die Aktivität durch vollständiges Löschen der vorherigen Instanz und Erstellen der neuen. Daher sollten App-Entwickler vorsichtig sein, wenn sie beispielsweise neue Aktivitäten über Lebenszyklus-Callbacks starten.
- Geräte müssen die Benutzeroberfläche für Fenstererweiterungen enthalten, um das Einbetten von Aktivitäten zu unterstützen. Fast alle Geräte mit großem Display mit Android 12L (API-Level) 32) oder höher enthalten die Schnittstelle. Einige Geräte mit großem Display, auf denen nicht mehrere Aktivitäten ausgeführt werden können, haben jedoch keine Benutzeroberfläche für Fenstererweiterungen. Wenn ein Gerät mit großem Bildschirm den Multifenstermodus nicht unterstützt, wird möglicherweise auch das Einbetten von Aktivitäten nicht unterstützt.
Weitere Informationen
- Codelabs:
- Lernpfad – Aktivitätseinbettung
- Beispiel-App – activity-embedding