Dostosuj przejście elementów wspólnych

Aby dostosować sposób wyświetlania udostępnianej animacji przejścia elementu, parametrów, które pozwalają zmienić sposób przejścia udostępnianych elementów.

Specyfikacja animacji

Aby zmienić specyfikację animacji służącą do określania rozmiaru i pozycji obrazu, możesz użyć opcji określić inny parametr boundsTransform w elemencie Modifier.sharedElement(). W ten sposób określasz początkową pozycję Rect i docelową pozycję Rect.

Aby na przykład tekst z poprzedniego przykładu przesuwał się wraz z łukiem motion, określ parametr boundsTransform, by użyć specyfikacji keyframes:

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
    )
)

Możesz użyć dowolnego elementu AnimationSpec. W tym przykładzie użyto specyfikacji keyframes.

Rysunek 1. Przykład przedstawiający różne parametry parametru boundsTransform

Tryb zmiany rozmiaru

Podczas animowania między 2 wspólnymi granicami możesz ustawić parametr resizeMode na RemeasureToBounds lub ScaleToBounds. Ten parametr określa sposób czyli przejścia między tymi dwoma stanami. Pierwsze ScaleToBounds mierzy układ podrzędny z ograniczeniami (lub elementami docelowymi) z wyprzedzeniem. Później stabilny układ dziecka jest skalowany tak, aby pasował do wspólnych granic. Element ScaleToBounds można określić jako „skalę graficzną” między stanami.

Z kolei RemeasureToBounds ponownie mierzy i przekazuje układ podrzędny sharedBounds z animowanymi stałymi ograniczeniami na podstawie rozmiaru docelowego. Ponowne pomiary są wywoływane przez zmianę rozmiaru granic, która może potencjalnie wystąpić w każdej klatce.

W przypadku Text komponentów kompozycyjnych zalecamy użycie ScaleToBounds, ponieważ pozwala to uniknąć przekazywania i układanie tekstu w różne wiersze. Jeśli chcesz uzyskać płynne przejście między 2 elementami, których współczynniki proporcji są różne, zalecamy użycie RemeasureToBounds.

Różnica między tymi dwoma trybami widać w przykładach poniżej:

ScaleToBounds

RemeasureToBounds

Przejdź do ostatecznego układu

Domyślnie przy przechodzeniu między 2 układami rozmiar układu jest animowany. między stanem początkowym i końcowym. Może to być niepożądane, gdy animowanie treści, np. tekstu.

Poniższy przykład ilustruje tekst opisu „Lorem Ipsum” Wprowadzanie na dwa różne sposoby. W pierwszym przykładzie tekst jest przeformatowywany, gdy wchodzi do kontenera, który zwiększa swój rozmiar, a w drugim przykładzie tekst nie jest przeformatowywany, gdy rośnie. Dodanie tych elementów (Modifier.skipToLookaheadSize()) uniemożliwi przeformatowanie w miarę wzrostu.

No Modifier.skipToLookahead() – zwróć uwagę na funkcję „Lorem Ipsum” zmiana przepływu tekstu

Modifier.skipToLookahead() – zwróć uwagę na funkcję „Lorem Ipsum” tekst zachowuje końcowy stan na początku animacji

Klip i nakładki

Podczas tworzenia elementów współdzielonych w komponencie należy pamiętać, że aby można było je udostępniać między różnymi komponentami, renderowanie komponentu jest podnoszone do nakładki warstwy, gdy rozpoczyna się przejście do jego odpowiednika na stronie docelowej. W efekcie wykracza poza granice obiektu nadrzędnego i jego przekształceń warstwy (np. alfa i skali).

Element będzie renderowany na wierzchu innych elementów interfejsu, które nie są współdzielone. Gdy przejście się zakończy, element zostanie usunięty z nakładki i przeniesiony do własnej DrawScope.

Aby przyciąć udostępniony element do kształtu, użyj standardowego Modifier.clip() . Umieść go za elementem 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
)

Jeśli chcesz mieć pewność, że udostępniony element nigdy nie będzie renderowany poza nadrzędnym kontenerem, możesz ustawić clipInOverlayDuringTransitionsharedElement(). Domyślnie w przypadku zagnieżdżonych wspólnych zakresów clipInOverlayDuringTransition używa ścieżki klipu z folderu nadrzędnego sharedBounds().

Aby zapewnić, że określone elementy interfejsu, np. dolna belka lub pływający przycisk, będą zawsze widoczne u góry podczas przejścia do elementu współdzielonego, użyj atrybutu Modifier.renderInSharedTransitionScopeOverlay(). Domyślnie ta wartość powoduje, że treść jest wyświetlana na nakładce w czasie, gdy jest udostępniana przejście jest aktywne.

Na przykład w Jetsnack obiekt BottomAppBar musi znaleźć się na elemencie do momentu, gdy ekran stanie się niewidoczny. Dodawanie modyfikatora kompozycyjne, pozostaje w górę.

Bez: Modifier.renderInSharedTransitionScopeOverlay()

Przez: Modifier.renderInSharedTransitionScopeOverlay()

Czasami możesz chcieć, aby Twoja nieudostępniona funkcja kompozycyjna była animowana pozostaje nad innymi kompozycjami przed przejściem. W takich przypadkach użyj wartości renderInSharedTransitionScopeOverlay().animateEnterExit(), aby animować composable out podczas przejścia wspólnego elementu:

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

Rys. 2. Dolny pasek aplikacji przesuwający się w górę i z poziomu animacji

W rzadkich przypadkach, gdy nie chcesz, by udostępniany element był renderowany w można ustawić renderInOverlayDuringTransition na sharedElement() na fałsz.

Powiadamianie układów równorzędnych o zmianach rozmiaru udostępnianych elementów

Domyślnie sharedBounds() i sharedElement() nie powiadamiają rodziców kontener o dowolnym rozmiarze zmienia się wraz z przejściem układu.

Aby rozpowszechnić zmiany rozmiaru w kontenerze nadrzędnym podczas przejścia, zmień parametr placeHolderSize na PlaceHolderSize.animatedSize. Wykonuję powoduje więc powiększanie lub pomniejszanie elementu. Wszystkie inne elementy układu reagują na tę zmianę.

PlaceholderSize.contentSize (domyślnie)

PlaceholderSize.animatedSize

(Zwróć uwagę, jak pozostałe elementy na liście przesuwają się w dół w odpowiedzi na rosnącą pozycję jednego elementu).