Para personalizar la forma en que se ejecuta la animación de transición de elementos compartidos, hay algunos parámetros que se pueden usar para cambiar la forma en que se realiza la transición de los elementos compartidos.
Especificación de animación
Para cambiar la especificación de animación que se usa para el movimiento de tamaño y posición, puedes especificar un parámetro boundsTransform
diferente en Modifier.sharedElement()
.
Esto proporciona la posición inicial Rect
y la posición objetivo Rect
.
Por ejemplo, para que el texto del ejemplo anterior se mueva con un movimiento de arco, especifica el parámetro boundsTransform
para usar una especificación 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 ) )
Puedes usar cualquier AnimationSpec
. En este ejemplo, se usa una especificación keyframes
.
boundsTransform
Modo de cambio de tamaño
Cuando se realiza una animación entre dos límites compartidos, puedes establecer el parámetro resizeMode
en RemeasureToBounds
o ScaleToBounds
. Este parámetro determina cómo el elemento compartido realiza la transición entre los dos estados. Primero, ScaleToBounds
mide el diseño secundario con las restricciones de anticipación (o destino). Luego, el diseño estable del elemento secundario se ajusta para que quepa en los límites compartidos.
ScaleToBounds
se puede considerar como una "escala gráfica" entre los estados.
En cambio, RemeasureToBounds
vuelve a medir y a diseñar el diseño secundario de sharedBounds
con restricciones fijas animadas basadas en el tamaño objetivo. La nueva medición se activa con el cambio de tamaño de los límites, que podría ocurrir en cada fotograma.
Para los elementos Text
componibles, se recomienda ScaleToBounds
, ya que evita el nuevo diseño y el reflujo del texto en diferentes líneas. RemeasureToBounds
se recomienda para límites con diferentes relaciones de aspecto y si deseas una continuidad fluida entre los dos elementos compartidos.
En los siguientes ejemplos, se puede observar la diferencia entre los dos modos de cambio de tamaño:
|
|
---|---|
Saltar al diseño final
De forma predeterminada, cuando se realiza una transición entre dos diseños, el tamaño del diseño se anima entre su estado inicial y final. Este comportamiento puede ser no deseado cuando se anima contenido, como texto.
En el siguiente ejemplo, se ilustra el texto de descripción "Lorem Ipsum" que aparece en la pantalla de dos maneras diferentes. En el primer ejemplo, el texto se redistribuye a medida que el contenedor aumenta de tamaño. En el segundo ejemplo, el texto no se redistribuye a medida que crece. Agregar Modifier.skipToLookaheadSize()
evita el reflujo a medida que crece.
Sin |
|
---|---|
Clips y superposiciones
Para que los elementos compartidos se compartan entre diferentes elementos componibles, la renderización del elemento componible se eleva a una superposición de capas cuando se inicia la transición a su coincidencia en el destino. El efecto de esto es que se escapará de los límites del elemento principal y de sus transformaciones de capa (por ejemplo, alfa y escala).
Se renderizará sobre otros elementos de la IU no compartidos. Una vez que finalice la transición, el elemento se quitará de la superposición y se colocará en su propio DrawScope
.
Para recortar un elemento compartido en una forma, usa la función Modifier.clip()
estándar. Colócalo después de 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 )
Si necesitas asegurarte de que un elemento compartido nunca se renderice fuera de un contenedor principal, puedes establecer clipInOverlayDuringTransition
en sharedElement()
. De forma predeterminada, para los límites compartidos anidados, clipInOverlayDuringTransition
usa la ruta de recorte del sharedBounds()
principal.
Para admitir que elementos específicos de la IU, como una barra inferior o un botón de acción flotante, permanezcan siempre en primer plano durante una transición de elementos compartidos, usa Modifier.renderInSharedTransitionScopeOverlay()
. De forma predeterminada, este modificador mantiene el contenido en la superposición durante el tiempo en que la transición compartida está activa.
Por ejemplo, en Jetsnack, el BottomAppBar
debe colocarse sobre el elemento compartido hasta que la pantalla deje de ser visible. Agregar el modificador al elemento componible lo mantiene elevado.
Sin |
Con |
---|---|
Es posible que desees que tu elemento componible no compartido también se anime para desaparecer y permanezca sobre los otros elementos componibles antes de la transición. En esos casos, usa renderInSharedTransitionScopeOverlay().animateEnterExit()
para animar el elemento componible a medida que se ejecuta la transición de elementos compartidos:
JetsnackBottomBar( modifier = Modifier .renderInSharedTransitionScopeOverlay( zIndexInOverlay = 1f, ) .animateEnterExit( enter = fadeIn() + slideInVertically { it }, exit = fadeOut() + slideOutVertically { it } ) )
En el caso poco frecuente de que no quieras que el elemento compartido se renderice en una superposición, puedes establecer renderInOverlayDuringTransition
en sharedElement()
como falso.
Notifica a los diseños secundarios los cambios en el tamaño del elemento compartido
De forma predeterminada, sharedBounds()
y sharedElement()
no notifican al contenedor principal sobre ningún cambio de tamaño a medida que se realiza la transición del diseño.
Para propagar los cambios de tamaño al contenedor principal a medida que realiza la transición, cambia el parámetro placeHolderSize
a PlaceHolderSize.animatedSize
. Si lo haces, el elemento crecerá o se encogerá. Todos los demás elementos del diseño responden al cambio.
|
(Observa cómo los demás elementos de la lista se mueven hacia abajo en respuesta al crecimiento de un elemento). |
---|---|