Wenn Sie die Animation für den Übergang des freigegebenen Elements anpassen möchten, können Sie einige Parameter verwenden, um den Übergang der freigegebenen Elemente zu ändern.
Spezifikationen für Animationen
Wenn Sie die Animationsspezifikation für die Größen- und Positionsänderung ändern möchten, können Sie für Modifier.sharedElement() einen anderen boundsTransform-Parameter angeben.
Dadurch werden die anfängliche Rect-Position und die Ziel-Rect-Position angegeben.
Wenn Sie beispielsweise den Text im vorherigen Beispiel in einer Bogenbewegung bewegen möchten, geben Sie den Parameter boundsTransform an, um eine keyframes-Spezifikation zu verwenden:
val textBoundsTransform = BoundsTransform { initialBounds, targetBounds -> keyframes { durationMillis = boundsAnimationDurationMillis initialBounds at 0 using ArcMode.ArcBelow using FastOutSlowInEasing targetBounds at boundsAnimationDurationMillis } } Text( "Cupcake", fontSize = 28.sp, modifier = Modifier.sharedBounds( rememberSharedContentState(key = "title"), animatedVisibilityScope = animatedVisibilityScope, boundsTransform = textBoundsTransform ) )
Sie können einen beliebigen AnimationSpec verwenden. In diesem Beispiel wird eine keyframes-Spezifikation verwendet.
boundsTransform-ParameternModus zum Ändern der Größe
Wenn Sie zwischen zwei gemeinsamen Grenzen animieren, können Sie den Parameter resizeMode entweder auf RemeasureToBounds oder ScaleToBounds festlegen. Dieser Parameter bestimmt, wie das freigegebene Element zwischen den beiden Zuständen wechselt. ScaleToBounds misst zuerst das untergeordnete Layout mit den Lookahead- (oder Ziel-)Einschränkungen. Anschließend wird das stabile Layout des untergeordneten Elements so skaliert, dass es in die gemeinsamen Grenzen passt.
ScaleToBounds kann man sich als „grafische Skala“ zwischen den Status vorstellen.
Im Gegensatz dazu werden bei RemeasureToBounds das untergeordnete Layout von sharedBounds mit animierten festen Einschränkungen basierend auf der Zielgröße neu gemessen und neu angeordnet. Die erneute Messung wird durch die Änderung der Begrenzungsgröße ausgelöst, was potenziell bei jedem Frame der Fall sein kann.
Für Text-Kompositionen wird ScaleToBounds empfohlen, da so ein neues Layout und ein Umbruch von Text in andere Zeilen vermieden werden. RemeasureToBounds wird für Grenzen mit unterschiedlichen Seitenverhältnissen empfohlen und wenn Sie eine flüssige Kontinuität zwischen den beiden freigegebenen Elementen wünschen.
Der Unterschied zwischen den beiden Modi zur Größenanpassung wird in den folgenden Beispielen veranschaulicht:
|
|
|---|---|
Gemeinsame Elemente dynamisch aktivieren und deaktivieren
Standardmäßig sind sharedElement() und sharedBounds() so konfiguriert, dass die Layoutänderungen animiert werden, wenn ein übereinstimmender Schlüssel im Zielzustand gefunden wird. Möglicherweise möchten Sie diese Animation jedoch dynamisch anhand bestimmter Bedingungen deaktivieren, z. B. der Navigationsrichtung oder des aktuellen UI-Status.
Wenn Sie festlegen möchten, ob der Übergang des freigegebenen Elements erfolgt, können Sie die an rememberSharedContentState() übergebene SharedContentConfig anpassen. Das Attribut isEnabled bestimmt, ob das freigegebene Element aktiv ist.
Im folgenden Beispiel wird gezeigt, wie Sie eine Konfiguration definieren, die den gemeinsamen Übergang nur beim Wechsel zwischen bestimmten Bildschirmen (z.B. nur von A nach B) aktiviert und für andere deaktiviert.
SharedTransitionLayout { val transition = updateTransition(currentState) transition.AnimatedContent { targetState -> // Create the configuration that depends on state changing. fun animationConfig() : SharedTransitionScope.SharedContentConfig { return object : SharedTransitionScope.SharedContentConfig { override val SharedTransitionScope.SharedContentState.isEnabled: Boolean // For this example, we only enable the transition in one direction // from A -> B and not the other way around. get() = transition.currentState == "A" && transition.targetState == "B" } } when (targetState) { "A" -> Box( modifier = Modifier .sharedElement( rememberSharedContentState( key = "shared_box", config = animationConfig() ), animatedVisibilityScope = this ) // ... ) { // Your content } "B" -> { Box( modifier = Modifier .sharedElement( rememberSharedContentState( key = "shared_box", config = animationConfig() ), animatedVisibilityScope = this ) // ... ) { // Your content } } } } }
Wenn ein freigegebenes Element während einer laufenden Animation deaktiviert wird, wird die aktuelle Animation standardmäßig trotzdem abgeschlossen, um zu verhindern, dass laufende Animationen versehentlich entfernt werden. Wenn Sie das Element während der Animation entfernen müssen, können Sie shouldKeepEnabledForOngoingAnimation in der SharedContentConfig-Schnittstelle überschreiben, um „false“ zurückzugeben.
Zum endgültigen Layout springen
Standardmäßig wird beim Übergang zwischen zwei Layouts die Layoutgröße zwischen dem Start- und dem Endzustand animiert. Dies kann bei der Animation von Inhalten wie Text unerwünscht sein.
Im folgenden Beispiel wird der Beschreibungstext „Lorem Ipsum“ auf zwei verschiedene Arten auf dem Bildschirm angezeigt. Im ersten Beispiel wird der Text beim Einfügen umgebrochen, während der Container größer wird. Im zweiten Beispiel wird der Text nicht umgebrochen, wenn er größer wird. Durch das Hinzufügen von Modifier.skipToLookaheadSize() wird verhindert, dass sich der Textfluss ändert, wenn der Text länger wird.
Nein, |
|
|---|---|
Clip und Overlays
Damit freigegebene Elemente zwischen verschiedenen komponierbaren Funktionen geteilt werden können, wird das Rendering der komponierbaren Funktion in ein Ebenen-Overlay verschoben, wenn der Übergang zum entsprechenden Element im Ziel gestartet wird. Dadurch werden die Grenzen des übergeordneten Elements und seine Ebenentransformationen (z. B. Alpha und Skalierung) umgangen.
Es wird über anderen nicht freigegebenen UI-Elementen gerendert. Nach Abschluss des Übergangs wird das Element aus dem Overlay in ein eigenes DrawScope verschoben.
Wenn Sie ein freigegebenes Element auf eine Form zuschneiden möchten, verwenden Sie die Standardfunktion Modifier.clip(). Fügen Sie es nach dem sharedElement() ein:
Image( painter = painterResource(id = R.drawable.cupcake), contentDescription = "Cupcake", modifier = Modifier .size(100.dp) .sharedElement( rememberSharedContentState(key = "image"), animatedVisibilityScope = this@AnimatedContent ) .clip(RoundedCornerShape(16.dp)), contentScale = ContentScale.Crop )
Wenn Sie sicherstellen möchten, dass ein freigegebenes Element nie außerhalb eines übergeordneten Containers gerendert wird, können Sie clipInOverlayDuringTransition für sharedElement() festlegen. Standardmäßig verwendet clipInOverlayDuringTransition für verschachtelte gemeinsame Grenzen den Clip-Pfad des übergeordneten sharedBounds().
Wenn Sie bestimmte UI-Elemente wie eine untere Leiste oder einen unverankerten Aktionsbutton während eines Übergangs mit gemeinsam genutzten Elementen immer im Vordergrund halten möchten, verwenden Sie Modifier.renderInSharedTransitionScopeOverlay(). Standardmäßig behält dieser Modifikator den Inhalt im Overlay, während der gemeinsame Übergang aktiv ist.
In Jetsnack muss die BottomAppBar beispielsweise so lange über dem freigegebenen Element platziert werden, bis der Bildschirm nicht mehr sichtbar ist. Wenn Sie den Modifikator zur zusammensetzbaren Funktion hinzufügen, bleibt sie erhöht.
Ohne |
Mit |
|---|---|
Möglicherweise möchten Sie, dass das nicht freigegebene Compose-Element vor dem Übergang sowohl animiert wird als auch über den anderen Compose-Elementen bleibt. Verwenden Sie in solchen Fällen renderInSharedTransitionScopeOverlay().animateEnterExit(), um die Animation der zusammensetzbaren Funktion zu beenden, während der Übergang des freigegebenen Elements ausgeführt wird:
JetsnackBottomBar( modifier = Modifier .renderInSharedTransitionScopeOverlay( zIndexInOverlay = 1f, ) .animateEnterExit( enter = fadeIn() + slideInVertically { it }, exit = fadeOut() + slideOutVertically { it } ) )
In seltenen Fällen, in denen das freigegebene Element nicht in einem Overlay gerendert werden soll, können Sie renderInOverlayDuringTransition für sharedElement() auf „false“ setzen.
Geschwisterlayouts über Änderungen an der Größe des freigegebenen Elements benachrichtigen
Standardmäßig benachrichtigen sharedBounds() und sharedElement() den übergeordneten Container nicht über Größenänderungen während des Layoutübergangs.
Wenn Sie Größenänderungen während des Übergangs an den übergeordneten Container weitergeben möchten, ändern Sie den Parameter placeholderSize in PlaceholderSize.AnimatedSize. Dadurch wird das Element vergrößert oder verkleinert. Alle anderen Elemente im Layout reagieren auf die Änderung.
|
(Beachten Sie, wie sich die anderen Elemente in der Liste nach unten verschieben, wenn ein Element größer wird.) |
|---|---|