Aby dostosować sposób działania animacji przejścia elementu współdzielonego, możesz użyć kilku parametrów.
Specyfikacja animacji
Aby zmienić specyfikację animacji używaną do zmiany rozmiaru i pozycji, możesz podać inny parametr boundsTransform
w pliku Modifier.sharedElement()
.
To daje początkową pozycję Rect
i docelową pozycję Rect
.
Aby na przykład tekst w poprzednim przykładzie poruszał się po łuku, użyj parametru boundsTransform
, aby 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
.
boundsTransform
parametryTryb zmiany rozmiaru
Podczas animacji między 2 współdzielonemi granicami możesz ustawić parametr resizeMode
na RemeasureToBounds
lub ScaleToBounds
. Ten parametr określa sposób przechodzenia elementu wspólnego między tymi dwoma stanami. ScaleToBounds
najpierw mierzy układ podrzędny z zastosowaniem ograniczeń wyprzedzających (lub docelowych). Następnie stabilny układ podrzędnego jest skalowany, aby zmieścić się w wspólnych granicach.
ScaleToBounds
można traktować jako „skala graficzna” między stanami.
Natomiast RemeasureToBounds
ponownie mierzy i układa 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 komponentów Text
zalecamy użycie ScaleToBounds
, ponieważ zapobiega to ponownemu rozmieszczaniu i przepływaniu tekstu na inne wiersze. RemeasureToBounds
jest zalecana w przypadku ramek o różnych współczynnikach proporcji, jeśli chcesz uzyskać płynne przejście między 2 współdzielanymi elementami.
Różnicę między tymi dwoma trybami zmiany rozmiaru widać w poniższych przykładach:
|
|
---|---|
Przejdź do układu końcowego
Domyślnie podczas przechodzenia między 2 widokami rozmiar układu przechodzi od stanu początkowego do końcowego. Może to być niepożądane zachowanie podczas animowania treści, takich jak tekst.
W tym przykładzie tekst „Lorem Ipsum” pojawia się na ekranie na 2 sposoby. W pierwszym przykładzie tekst jest ponownie formatowany, gdy wchodzi do kontenera, który zwiększa swój rozmiar. W drugim przykładzie tekst nie jest przeformatowywany, gdy się wydłuża. Dodanie Modifier.skipToLookaheadSize()
zapobiega przepływowi treści na inne wiersze w miarę wzrostu treści.
Nie |
|
---|---|
Klip i nakładki
Aby udostępnione elementy mogły być udostępniane między różnymi komponentami, renderowanie komponentu jest podwyższane do nakładki warstwy, gdy rozpoczyna się przejście do jego dopasowania w miejscu docelowym. W efekcie element ten wyjdzie poza granice elementu nadrzędnego i jego przekształceń warstwy (np. alfa i skali).
Będzie on renderowany na wierzchu innych elementów interfejsu, które nie są współdzielone. 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 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ć clipInOverlayDuringTransition
w sharedElement()
. Domyślnie w przypadku zaokrąglonych zakresów współdzielonych clipInOverlayDuringTransition
używa ścieżki klipu z nadrzędnego sharedBounds()
.
Aby zapewnić, że określone elementy interfejsu, np. pasek dolny 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 ten modyfikator zachowuje zawartość nakładki przez cały czas trwania wspólnej animacji przejścia.
Na przykład w Jetsnackie element BottomAppBar
musi być umieszczony na wierzchu elementu współdzielonego, dopóki ekran nie stanie się niewidoczny. Dodanie modyfikatora do komponentu powoduje, że pozostaje on w pozycji wysuniętej.
Bez |
Przez: |
---|---|
Możesz chcieć, aby nieudostępnione komponenty były animowane i pozostawały na wierzchu innych komponentów przed przejściem. W takich przypadkach użyj funkcji renderInSharedTransitionScopeOverlay().animateEnterExit()
, aby animować kompozyt podczas przejścia elementu współdzielonego:
JetsnackBottomBar( modifier = Modifier .renderInSharedTransitionScopeOverlay( zIndexInOverlay = 1f, ) .animateEnterExit( enter = fadeIn() + slideInVertically { it }, exit = fadeOut() + slideOutVertically { it } ) )
W rzadkich przypadkach, gdy nie chcesz, aby udostępniony element był renderowany w nakładce, możesz ustawić wartość parametru renderInOverlayDuringTransition
w elementach sharedElement()
na „false” (fałsz).
Informowanie układów nadrzędnych o zmianach rozmiaru współdzielonego elementu
Domyślnie sharedBounds()
i sharedElement()
nie powiadamią kontenera nadrzędnego o żadnych zmianach rozmiaru podczas przechodzenia między układami.
Aby rozpowszechnić zmiany rozmiaru w kontenerze nadrzędnym podczas przejścia, zmień parametr placeHolderSize
na PlaceHolderSize.animatedSize
. Spowoduje to powiększenie lub pomniejszenie elementu. Wszystkie inne elementy układu reagują na tę zmianę.
|
(Zwróć uwagę, jak inne elementy na liście przesuwają się w dół w odpowiedzi na wzrost jednego elementu) |
---|---|