Aby dostosować sposób działania animacji przejścia elementu współdzielonego, możesz użyć kilku parametrów, które pozwolą zmienić sposób przejścia elementów współdzielonych.
Specyfikacja animacji
Aby zmienić specyfikację animacji używaną do ruchu rozmiaru i pozycji, możesz określić inny parametr boundsTransform w pliku Modifier.sharedElement().
Podaje to początkową pozycję Rect i docelową pozycję Rect.
Aby na przykład tekst z poprzedniego przykładu poruszał się po łuku, użyj parametru boundsTransform, aby zastosować specyfikację 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 AnimationSpec. W tym przykładzie użyto specyfikacji keyframes.
boundsTransformparametryTryb zmiany rozmiaru
Podczas animowania między 2 wspólnymi granicami możesz ustawić parametr resizeMode na RemeasureToBounds lub ScaleToBounds. Ten parametr określa, w jaki sposób element współdzielony przechodzi między dwoma stanami. ScaleToBounds najpierw mierzy układ elementu podrzędnego z użyciem ograniczeń wyprzedzających (lub docelowych). Następnie stabilny układ elementu podrzędnego jest skalowany tak, aby zmieścił się w udostępnionych granicach.
ScaleToBounds można traktować jako „skalę graficzną” między stanami.
Natomiast RemeasureToBounds ponownie mierzy i układa układ podrzędny sharedBounds z animowanymi stałymi ograniczeniami na podstawie rozmiaru docelowego. Ponowny pomiar jest wywoływany przez zmianę rozmiaru granic, co może następować w każdej klatce.
W przypadku komponentów kompozycyjnych Text zalecamy używanie ScaleToBounds, ponieważ pozwala to uniknąć ponownego układania i przelewania tekstu do innych wierszy. RemeasureToBounds jest zalecane w przypadku granic o różnych współczynnikach proporcji oraz jeśli chcesz uzyskać płynną ciągłość między 2 wspólnymi elementami.
Różnicę między tymi 2 trybami zmiany rozmiaru widać w przykładach poniżej:
|
|
|---|---|
Dynamiczne włączanie i wyłączanie elementów udostępnionych
Domyślnie sharedElement() i sharedBounds() są skonfigurowane tak, aby animować zmiany układu, gdy w stanie docelowym zostanie znaleziony pasujący klucz. Możesz jednak dynamicznie wyłączać tę animację w określonych warunkach, np. w zależności od kierunku nawigacji lub bieżącego stanu interfejsu.
Aby określić, czy ma nastąpić przejście elementu udostępnionego, możesz dostosować wartość SharedContentConfig przekazywaną do rememberSharedContentState(). Właściwość isEnabled
określa, czy element udostępniony jest aktywny.
Poniższy przykład pokazuje, jak zdefiniować konfigurację, która włącza przejście udostępnione tylko podczas przechodzenia między określonymi ekranami (np. tylko z A do B), a wyłącza je w przypadku innych ekranów.
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 } } } } }
Domyślnie, jeśli udostępniony element zostanie wyłączony podczas trwającej animacji, animacja zostanie dokończona, aby zapobiec przypadkowemu usunięciu animacji w trakcie. Jeśli chcesz usunąć element podczas animacji, możesz zastąpić wartość shouldKeepEnabledForOngoingAnimation w interfejsie SharedContentConfig, aby zwrócić wartość false.
Przejdź do układu końcowego
Domyślnie podczas przechodzenia między dwoma układami rozmiar układu jest animowany między stanem początkowym a końcowym. Może to być niepożądane zachowanie podczas animowania treści, takich jak tekst.
Poniższy przykład pokazuje tekst opisu „Lorem Ipsum” pojawiający się na ekranie na 2 różne sposoby. W pierwszym przykładzie tekst jest ponownie formatowany w miarę pojawiania się w kontenerze, który się powiększa. W drugim przykładzie tekst nie zmienia układu w miarę powiększania się. Dodanie elementu Modifier.skipToLookaheadSize() zapobiega ponownemu przepływowi treści podczas powiększania.
Brak |
|
|---|---|
Klip i nakładki
Aby udostępniać elementy między różnymi funkcjami kompozycyjnymi, renderowanie funkcji kompozycyjnej jest przenoszone do nakładki warstwy, gdy rozpoczyna się przejście do pasującego elementu w miejscu docelowym. Spowoduje to, że element wyjdzie poza granice elementu nadrzędnego i jego przekształcenia warstwy (np. alfa i skala).
Będzie się wyświetlać nad innymi nieudostępnionymi elementami interfejsu. Po zakończeniu przejścia element zostanie przeniesiony z nakładki do własnej DrawScope.
Aby przyciąć udostępniony element do kształtu, użyj standardowej funkcji Modifier.clip(). Umieść go po znaku 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 kontenerem nadrzędnym, możesz ustawić clipInOverlayDuringTransition na sharedElement(). Domyślnie w przypadku zagnieżdżonych udostępnionych granic element clipInOverlayDuringTransition używa ścieżki przycinania z elementu nadrzędnego sharedBounds().
Aby podczas przejścia elementu udostępnionego zachować na wierzchu określone elementy interfejsu, takie jak pasek u dołu lub pływający przycisk działania, użyj Modifier.renderInSharedTransitionScopeOverlay(). Domyślnie ten modyfikator utrzymuje treść w nakładce w czasie, gdy aktywna jest udostępniona przejście.
Na przykład w aplikacji Jetsnack element BottomAppBar musi być umieszczony na elemencie współdzielonym, dopóki ekran nie będzie widoczny. Dodanie modyfikatora
do funkcji kompozycyjnej powoduje, że pozostaje ona na wierzchu.
Bez: |
Przez: |
|---|---|
Możesz chcieć, aby element kompozycyjny, który nie jest współdzielony, również animował się i pozostawał na wierzchu innych elementów kompozycyjnych przed przejściem. W takich przypadkach użyj funkcji renderInSharedTransitionScopeOverlay().animateEnterExit(), aby animować element kompozycyjny podczas przejścia elementu udostępnionego:
JetsnackBottomBar( modifier = Modifier .renderInSharedTransitionScopeOverlay( zIndexInOverlay = 1f, ) .animateEnterExit( enter = fadeIn() + slideInVertically { it }, exit = fadeOut() + slideOutVertically { it } ) )
W rzadkich przypadkach, gdy chcesz, aby udostępniony element nie był renderowany w nakładce, możesz ustawić wartość renderInOverlayDuringTransition w sharedElement() na false.
Powiadamianie układów równorzędnych o zmianach rozmiaru elementu udostępnionego
Domyślnie elementy sharedBounds() i sharedElement() nie powiadamiają kontenera nadrzędnego o żadnych zmianach rozmiaru podczas przejść układu.
Aby zmiany rozmiaru były propagowane do kontenera nadrzędnego podczas przejścia, zmień parametr placeHolderSize na PlaceHolderSize.animatedSize. W ten sposób możesz powiększyć lub pomniejszyć element. Wszystkie pozostałe elementy układu reagują na zmianę.
|
(Zwróć uwagę, jak pozostałe elementy listy przesuwają się w dół, gdy jeden z nich się powiększa). |
|---|---|