Para personalizar como a animação de transição do elemento compartilhado é executada, há alguns parâmetros que podem ser usados para mudar a transição desses elementos.
Especificações de animação
Para mudar a especificação de animação usada para o movimento de tamanho e posição, defina um parâmetro boundsTransform
diferente em Modifier.sharedElement()
.
Isso fornece a posição inicial de Rect
e a posição Rect
desejada.
Por exemplo, para fazer com que o texto no exemplo anterior se mova com um movimento
de arco, especifique o parâmetro boundsTransform
para usar uma especificação 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 ) )
Você pode usar qualquer AnimationSpec
. Este exemplo usa uma especificação keyframes
.
boundsTransform
.Modo de redimensionamento
Ao animar entre dois limites compartilhados, você pode definir o parâmetro resizeMode
como RemeasureToBounds
ou ScaleToBounds
. Esse parâmetro determina como
o elemento compartilhado faz a transição entre os dois estados. Primeiro,
o ScaleToBounds
mede o layout filho com as restrições de análise antecipada (ou destino). Em seguida,
o layout estável do filho é dimensionado para caber nos limites compartilhados.
ScaleToBounds
pode ser considerada uma "escala gráfica" entre os estados.
Já o RemeasureToBounds
mede e reorganiza o layout filho de
sharedBounds
com restrições fixas animadas com base no tamanho de destino. A
remedição é acionada pela mudança de tamanho dos limites, que pode
ser todos os frames.
Para elementos combináveis Text
, recomendamos usar ScaleToBounds
, porque isso evita que o texto seja remodelado
e reflow em linhas diferentes. Para limites com proporções diferentes
e se você quiser uma continuidade fluida entre os dois elementos compartilhados,
recomendamos RemeasureToBounds
.
A diferença entre os dois modos de redimensionamento pode ser vista nos exemplos a seguir:
|
|
---|---|
Pular para o layout final
Por padrão, ao fazer a transição entre dois layouts, o tamanho do layout é animado entre os estados inicial e final. Esse pode ser um comportamento indesejável ao animar conteúdo como texto.
O exemplo abaixo ilustra o texto de descrição "Lorem Ipsum" que entra
na tela de duas maneiras diferentes. No primeiro exemplo, o texto passa
à medida que o contêiner cresce. No segundo exemplo, o texto não
reflow à medida que cresce. A adição de Modifier.skipToLookaheadSize()
impede o reflow
à medida que ele cresce.
Sem Modifier.skipToLookahead() - observe o refluxo do texto "Lorem Ipsum" |
Modifier.skipToLookahead() - observe que o texto "Lorem Ipsum" mantém o estado final no início da animação |
---|---|
Recorte e sobreposições
Um conceito importante ao criar elementos compartilhados no Compose é que, para que eles sejam compartilhados entre diferentes elementos combináveis, a renderização do elemento combinável é elevada para uma sobreposição de camada quando a transição é iniciada para a correspondência no destino. O efeito disso é que ele escape dos limites do pai e das transformações de camada dele (por exemplo, alfa e escala).
Ele será renderizado sobre outros elementos de interface não compartilhados. Quando a transição for
concluída, o elemento será descartado da sobreposição para o próprio DrawScope
.
Para recortar um elemento compartilhado em uma forma, use a função
Modifier.clip()
padrão. Coloque-o depois 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 )
Se você precisar garantir que um elemento compartilhado nunca seja renderizado fora de um contêiner
pai, defina clipInOverlayDuringTransition
em sharedElement()
. Por
padrão, para limites compartilhados aninhados, clipInOverlayDuringTransition
usa o caminho
de corte do sharedBounds()
pai.
Para oferecer suporte à manutenção de elementos da interface específicos, como uma barra inferior ou um botão de ação
flutuante, sempre na parte de cima durante uma transição de elemento compartilhado, use
Modifier.renderInSharedTransitionScopeOverlay()
. Por padrão, esse
modificador mantém o conteúdo na sobreposição enquanto a transição
compartilhada está ativa.
Por exemplo, no Jetsnack, a BottomAppBar
precisa ser colocada sobre o
elemento compartilhado até que a tela não esteja visível. Adicionar o modificador
ao elemento combinável o mantém elevado.
Sem |
Com |
---|---|
Às vezes, você pode querer que o elemento combinável não compartilhado seja animado e
permaneça sobre os outros elementos antes da transição. Nesses casos, use
renderInSharedTransitionScopeOverlay().animateEnterExit()
para animar o
elemento combinável enquanto a transição do elemento compartilhado é executada:
JetsnackBottomBar( modifier = Modifier .renderInSharedTransitionScopeOverlay( zIndexInOverlay = 1f, ) .animateEnterExit( enter = fadeIn() + slideInVertically { it }, exit = fadeOut() + slideOutVertically { it } ) )
No caso raro em que você queira que seu elemento compartilhado não seja renderizado em uma
sobreposição, defina renderInOverlayDuringTransition
na sharedElement()
como "false".
Notificar layouts irmãos sobre mudanças no tamanho do elemento compartilhado
Por padrão, sharedBounds()
e sharedElement()
não notificam o contêiner
pai sobre mudanças de tamanho durante as transições do layout.
Para propagar mudanças de tamanho para o contêiner pai durante a transição,
mude o parâmetro placeHolderSize
para PlaceHolderSize.animatedSize
. Isso
faz com que o item aumente ou diminua. Todos os outros itens no layout respondem
à mudança.
|
Observe como os outros itens na lista se movem para baixo em resposta ao crescimento de um item. |
---|---|