Übergang zu gemeinsam genutzten Elementen anpassen

Um die Ausführung der Übergangsanimation für gemeinsame Elemente anzupassen, Parameter, mit denen sich der Übergang von gemeinsam genutzten Elementen ändern lässt.

Animationsspezifikation

Um die Animationsspezifikationen für die Größe und Positionsbewegung zu ändern, können Sie Einen anderen boundsTransform-Parameter für Modifier.sharedElement() angeben. So erhalten Sie die Anfangs- und Zielposition von Rect.

Um beispielsweise den Text im vorherigen Beispiel bogenförmig zu bewegen, Bewegung den Parameter boundsTransform, 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 eine beliebige AnimationSpec verwenden. In diesem Beispiel wird eine keyframes-Spezifikation verwendet.

Abbildung 1: Beispiel für verschiedene boundsTransform-Parameter

Modus zum Anpassen der Größe

Wenn Sie zwischen zwei gemeinsamen Grenzen animieren, können Sie den Parameter resizeMode auf RemeasureToBounds oder ScaleToBounds festlegen. Dieser Parameter bestimmt, wie wechselt das gemeinsame Element zwischen den beiden Zuständen. ScaleToBounds misst zuerst das untergeordnete Layout mit den Vorschau- (oder Ziel-)Einschränkungen. Anschließend wird das stabile Layout des untergeordneten Elements so skaliert, dass es in die gemeinsamen Grenzen passt. ScaleToBounds kann als „grafische Skala“ zwischen den Zuständen betrachtet werden.

Bei RemeasureToBounds wird das untergeordnete Layout von sharedBounds mit animierten festen Einschränkungen basierend auf der Zielgröße neu gemessen und neu angeordnet. Die Neumessung 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 dadurch ein Neulayout und ein Neufluss von Text auf verschiedene Zeilen vermieden wird. Wenn die Grenzen unterschiedliche Seitenverhältnisse haben und Sie eine flüssige Kontinuität zwischen den beiden gemeinsamen Elementen wünschen, wird RemeasureToBounds empfohlen.

Die Unterschiede zwischen den beiden Modi zum Ändern der Größe sind in den folgenden Beispielen zu sehen:

ScaleToBounds

RemeasureToBounds

Zum endgültigen Layout springen

Standardmäßig wird beim Übergang zwischen zwei Layouts die Layoutgröße zwischen dem Start- und dem Endstatus animiert. Dies kann unerwünschtes Verhalten sein, wenn zum Animieren von Inhalten wie Text.

Das folgende Beispiel zeigt den Beschreibungstext „Lorem Ipsum“ betreten auf zwei unterschiedliche Arten. Im ersten Beispiel wird der Text umgefaltet, während er mit zunehmender Größe des Containers ein. Im zweiten Beispiel Reflow anwenden, wenn er wächst. Durch Hinzufügen von Modifier.skipToLookaheadSize() wird ein Reflow verhindert. wenn er wächst.

Ohne Modifier.skipToLookahead() – beachten Sie, dass der Text „Lorem Ipsum“ neu formatiert wird

Modifier.skipToLookahead(): Der Text „Lorem Ipsum“ behält seinen Endstatus zu Beginn der Animation bei.

Clips und Overlays

Ein wichtiges Konzept beim Erstellen gemeinsam genutzter Elemente in Compose ist, dass sie zwischen verschiedenen Compose-Elementen freigegeben werden können, wenn das Rendering des Compose-Elements in ein Ebenen-Overlay verschoben wird, wenn der Übergang zu seiner Übereinstimmung im Ziel gestartet wird. Das hat zur Folge, dass die Grenzen des übergeordneten Elements und seine Ebenentransformationen (z. B. Alpha und Skalierung) umgangen werden.

Es wird über anderen nicht freigegebenen UI-Elementen gerendert. Sobald die Umstellung abgeschlossen ist, wird das Element aus dem Overlay in sein eigenes DrawScope verschoben.

Wenn Sie ein freigegebenes Element zu einer Form zuschneiden möchten, verwenden Sie die Standardfunktion Modifier.clip(). Platziere ihn nach sharedElement():

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üssen, dass ein gemeinsam genutztes Element nie außerhalb eines übergeordneten Elements gerendert wird Container enthält, können Sie clipInOverlayDuringTransition auf sharedElement() festlegen. Standardmäßig verwendet clipInOverlayDuringTransition für verschachtelte gemeinsame Begrenzungen den Clippfad des übergeordneten sharedBounds().

Wenn bestimmte UI-Elemente wie eine untere Leiste oder eine schwebende Aktionsschaltfläche während eines Übergangs von gemeinsamen Elementen immer oben bleiben sollen, verwenden Sie Modifier.renderInSharedTransitionScopeOverlay(). Standardmäßig bleiben die Inhalte im Overlay, solange die gemeinsame Überblendung aktiv ist.

In Jetsnack muss das BottomAppBar beispielsweise über dem gemeinsamen Element platziert werden, bis der Bildschirm nicht mehr sichtbar ist. Wenn Sie den Modifier zum Composeable hinzufügen, bleibt es hervorgehoben.

Ohne Modifier.renderInSharedTransitionScopeOverlay()

Mit Modifier.renderInSharedTransitionScopeOverlay()

Vielleicht möchten Sie die nicht freigegebene zusammensetzbare Funktion vor dem Übergang zu den anderen zusammensetzbaren Funktionen übernehmen. Verwenden Sie in solchen Fällen renderInSharedTransitionScopeOverlay().animateEnterExit(), um das Zusammenspiel der Elemente zu animieren, während die Überblendung des freigegebenen Elements ausgeführt wird:

JetsnackBottomBar(
    modifier = Modifier
        .renderInSharedTransitionScopeOverlay(
            zIndexInOverlay = 1f,
        )
        .animateEnterExit(
            enter = fadeIn() + slideInVertically {
                it
            },
            exit = fadeOut() + slideOutVertically {
                it
            }
        )
)

Abbildung 2: Untere App-Leiste, die beim Übergang der Animation ein- und ausgeblendet wird

In dem seltenen Fall, dass Ihr gemeinsam genutztes Element nicht in einem Overlay ist, kannst du renderInOverlayDuringTransition auf sharedElement() festlegen auf false setzen.

Über Änderungen an der Größe gemeinsam genutzter Elemente benachrichtigen

Standardmäßig benachrichtigen sharedBounds() und sharedElement() die Eltern nicht Container mit Größenänderungen, die sich beim Übergang des Layouts ändern.

Damit Größenänderungen beim Übergang an den übergeordneten Container weitergegeben werden, Ä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.

PlaceholderSize.contentSize (Standard)

PlaceholderSize.animatedSize

Beachten Sie, dass sich die anderen Elemente in der Liste nach unten bewegen, wenn ein Element größer wird.