Übergang zu gemeinsam genutzten Elementen anpassen

Es gibt einige Parameter, mit denen Sie den Übergang der gemeinsam genutzten Elemente ändern können.

Animationsspezifikation

Wenn Sie die Animationsspezifikation für die Größe und Positionsbewegung ändern möchten, können Sie einen anderen boundsTransform-Parameter für Modifier.sharedElement() angeben. Damit werden die Rect-Anfangsposition und die Rect-Zielposition angegeben.

Damit sich der Text im vorherigen Beispiel beispielsweise mit einer Bogenbewegung bewegt, 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.

Abbildung 1: Beispiel für verschiedene boundsTransform-Parameter

Modus zum Ändern der Größe

Wenn Sie Animationen zwischen zwei gemeinsamen Grenzen erstellen, können Sie den resizeMode-Parameter entweder auf RemeasureToBounds oder ScaleToBounds festlegen. Dieser Parameter bestimmt, wie das gemeinsame Element zwischen den beiden Zuständen wechselt. ScaleToBounds misst zuerst das untergeordnete Layout mit den Lookahead-Einschränkungen (oder Zieleinschränkungen). Dann wird das stabile Layout des untergeordneten Elements so skaliert, dass es in die gemeinsamen Grenzen passt. ScaleToBounds kann als eine grafische Skala zwischen den Staaten betrachtet werden.

Im Gegensatz dazu misst RemeasureToBounds das untergeordnete Layout von sharedBounds mit animierten festen Einschränkungen basierend auf der Zielgröße und passt es neu an. Die erneute Messung wird durch die Änderung der Grenzen der Größe ausgelöst. Diese kann möglicherweise jeden Frame sein.

Für zusammensetzbare Funktionen von Text wird ScaleToBounds empfohlen, da damit das Layout und die Umbrüche des Texts in verschiedenen Zeilen vermieden werden. Für Grenzen, die sich in unterschiedlichen Seitenverhältnissen befinden, und für eine fließende Kontinuität zwischen den beiden gemeinsam genutzten Elementen wird RemeasureToBounds empfohlen.

Der Unterschied zwischen den beiden Größenänderungsmodi ist in den folgenden Beispielen zu sehen:

ScaleToBounds

RemeasureToBounds

Zum endgültigen Layout springen

Beim Wechsel zwischen zwei Layouts wird standardmäßig die Layoutgröße zwischen dem Start- und Endzustand animiert. Dies kann bei Animationen von Inhalten wie Text zu unerwünschtem Verhalten führen.

Das folgende Beispiel zeigt, wie der Beschreibungstext „Lorem Ipsum“ auf zwei verschiedene Arten in den Bildschirm gelangt. Im ersten Beispiel ändert sich der Text automatisch, wenn der Container größer wird. Im zweiten Beispiel ändert sich der Text nicht automatisch. Durch Hinzufügen von Modifier.skipToLookaheadSize() wird der Umbruch während des Wachstums verhindert.

No Modifier.skipToLookahead() – Beachte, dass sich der Text „Lorem Ipsum“ ändert

Modifier.skipToLookahead(): Beachte, dass der Text „Lorem Ipsum“ am Anfang der Animation seinen endgültigen Zustand beibehält.

Clip und Overlays

Ein wichtiges Konzept beim Erstellen gemeinsam verwendeter Elemente in Compose besteht darin, dass für eine gemeinsame Nutzung durch verschiedene zusammensetzbare Funktionen das Rendering der zusammensetzbaren Funktion zu einem Ebenen-Overlay erhöht wird, wenn der Übergang zu der Übereinstimmung mit dem Ziel im Ziel gestartet wird. Dies hat zur Folge, dass die übergeordneten Grenzen und die zugehörigen Ebenentransformationen (z. B. Alpha und Maßstab) übersprungen werden.

Es wird über anderen nicht geteilten UI-Elementen gerendert. Nach dem Übergang wird das Element aus dem Overlay auf sein eigenes DrawScope-Element entfernt.

Verwenden Sie die Standardfunktion Modifier.clip(), um ein gemeinsam genutztes Element an eine Form zuzuschneiden. Platzieren Sie es 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 ein freigegebenes Element nie außerhalb eines übergeordneten Containers gerendert werden soll, können Sie clipInOverlayDuringTransition auf sharedElement() festlegen. Standardmäßig verwendet clipInOverlayDuringTransition bei verschachtelten gemeinsamen Grenzen den Clippfad des übergeordneten sharedBounds().

Wenn bestimmte UI-Elemente wie z. B. eine Leiste am unteren Rand oder eine unverankerte Aktionsschaltfläche, die beim Übergang eines gemeinsamen Elements immer oben angezeigt werden soll, immer oben angezeigt werden sollen, verwenden Sie Modifier.renderInSharedTransitionScopeOverlay(). Standardmäßig behält dieser Modifizierer den Inhalt im Overlay für die Zeit bei, in der der gemeinsame Übergang aktiv ist.

In Jetsnack muss das BottomAppBar beispielsweise so lange über dem gemeinsam genutzten Element platziert werden, bis der Bildschirm nicht sichtbar ist. Durch das Hinzufügen des Modifikators auf die zusammensetzbare Funktion bleibt sie erhöht.

Ohne Modifier.renderInSharedTransitionScopeOverlay()

Mit Modifier.renderInSharedTransitionScopeOverlay()

Es kann vorkommen, dass Sie eine nicht freigegebene zusammensetzbare Funktion vor der Umstellung mit Animationen versehen oder auf den anderen zusammensetzbaren Funktionen bleiben möchten. Verwenden Sie in solchen Fällen renderInSharedTransitionScopeOverlay().animateEnterExit(), um die zusammensetzbare Funktion zu animieren, während der Übergang des gemeinsamen 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 sich beim Übergang der Animation ein- und ausbewegt

In dem seltenen Fall, dass Ihr gemeinsam genutztes Element nicht in einem Overlay gerendert werden soll, können Sie renderInOverlayDuringTransition für sharedElement() auf „false“ setzen.

Benachrichtigung gleichgeordneter Layouts bei Änderungen an der Größe gemeinsam genutzter Elemente

Standardmäßig wird der übergeordnete Container von sharedBounds() und sharedElement() nicht über Größenänderungen benachrichtigt, wenn das Layout gewechselt wird.

Damit Größenänderungen beim Übergang an den übergeordneten Container übernommen werden, müssen Sie den Parameter placeHolderSize in PlaceHolderSize.animatedSize ändern. Dadurch wird das Element vergrößert oder verkleinert. Alle anderen Elemente im Layout reagieren auf die Änderung.

PlaceholderSize.contentSize (Standard)

PlaceholderSize.animatedSize

(Beachten Sie, wie die anderen Elemente in der Liste nach unten verschoben werden, wenn ein Element größer wird.)