Чтобы настроить способ запуска анимации перехода общих элементов, существует несколько параметров, которые можно использовать для изменения способа перехода общих элементов.
Спецификация анимации
Чтобы изменить спецификацию анимации, используемую для перемещения размера и положения, вы можете указать другой boundsTransform
в Modifier.sharedElement()
. Это обеспечивает начальную позицию Rect
и целевую позицию Rect
.
Например, чтобы текст в предыдущем примере перемещался по дуге, укажите boundsTransform
, чтобы использовать спецификацию 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 ) )
Вы можете использовать любую AnimationSpec
. В этом примере используется спецификация keyframes
.
Режим изменения размера
При анимации между двумя общими границами вы можете установить для параметра resizeMode
значение RemeasureToBounds
или ScaleToBounds
. Этот параметр определяет, как общий элемент переходит между двумя состояниями. ScaleToBounds
сначала измеряет дочерний макет с ограничениями просмотра вперед (или целевыми). Затем стабильный макет дочернего элемента масштабируется, чтобы соответствовать общим границам. ScaleToBounds
можно рассматривать как «графическую шкалу» между состояниями.
В то время как RemeasureToBounds
повторно измеряет и изменяет макет дочернего макета sharedBounds
с анимированными фиксированными ограничениями на основе целевого размера. Повторное измерение инициируется изменением размера границ, которое потенциально может происходить в каждом кадре.
Для составных элементов Text
рекомендуется ScaleToBounds
, поскольку он позволяет избежать ретрансляции и перекомпоновки текста в разные строки. Для границ с разными соотношениями сторон и если вы хотите обеспечить плавную непрерывность между двумя общими элементами, рекомендуется использовать RemeasureToBounds
.
Разницу между двумя режимами изменения размера можно увидеть в следующих примерах:
| |
---|---|
Перейти к окончательному макету
По умолчанию при переходе между двумя макетами размер макета анимируется между его начальным и конечным состоянием. Это может быть нежелательным поведением при анимации содержимого, например текста.
Следующий пример иллюстрирует появление текста описания «Lorem Ipsum» на экране двумя разными способами. В первом примере текст перестраивается при входе по мере увеличения размера контейнера, во втором примере текст не перестраивается по мере увеличения. Добавление Modifier.skipToLookaheadSize()
предотвращает перекомпоновку по мере ее роста.
Нет Modifier.skipToLookahead() — обратите внимание на перекомпоновку текста «Lorem Ipsum». | Modifier.skipToLookahead() — обратите внимание, что текст «Lorem Ipsum» сохраняет свое окончательное состояние в начале анимации. |
---|---|
Клип и наложения
Важная концепция при создании общих элементов в Compose заключается в том, что для того, чтобы они могли совместно использоваться различными составными объектами, рендеринг составного объекта повышается до уровня наложения слоев, когда начинается переход до его соответствия в месте назначения. Эффект от этого заключается в том, что он выйдет за границы родительского элемента и преобразования его слоев (например, альфа и масштаб).
Он будет отображаться поверх других элементов пользовательского интерфейса, не являющихся общими, после завершения перехода элемент будет перенесен из наложения в собственный DrawScope
.
Чтобы прикрепить общий элемент к фигуре, используйте стандартную функцию Modifier.clip()
. Поместите его после 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 )
Если вам нужно гарантировать, что общий элемент никогда не будет отображаться за пределами родительского контейнера, вы можете установить clipInOverlayDuringTransition
в sharedElement()
. По умолчанию для вложенных общих границ clipInOverlayDuringTransition
использует путь клипа из родительского объекта sharedBounds()
.
Чтобы обеспечить сохранение определенных элементов пользовательского интерфейса, таких как нижняя панель или кнопка плавающего действия, всегда сверху во время перехода общего элемента, используйте Modifier.renderInSharedTransitionScopeOverlay()
. По умолчанию этот модификатор сохраняет содержимое в наложении в то время, когда общий переход активен.
Например, в Jetsnack BottomAppBar
необходимо размещать поверх общего элемента до тех пор, пока экран не станет видимым. Добавление модификатора к составному элементу сохраняет его повышенным.
Без | С помощью |
---|---|
Иногда вам может потребоваться, чтобы ваш необщий составной объект анимировался, а также оставался поверх других составных элементов до перехода. В таких случаях используйте renderInSharedTransitionScopeOverlay().animateEnterExit()
для анимации составного элемента при выполнении перехода общего элемента:
JetsnackBottomBar( modifier = Modifier .renderInSharedTransitionScopeOverlay( zIndexInOverlay = 1f, ) .animateEnterExit( enter = fadeIn() + slideInVertically { it }, exit = fadeOut() + slideOutVertically { it } ) )
В том редком случае, когда вы не хотите, чтобы ваш общий элемент отображался в наложении, вы можете установить renderInOverlayDuringTransition
в sharedElement()
значение false.
Уведомлять родственные макеты об изменениях размера общего элемента.
По умолчанию sharedBounds()
и sharedElement()
не уведомляют родительский контейнер о каких-либо изменениях размера при переходе макета.
Чтобы распространить изменения размера на родительский контейнер при его переходе, измените параметр placeHolderSize
на PlaceHolderSize.animatedSize
. Это приведет к тому, что элемент увеличится или уменьшится. Все остальные элементы макета реагируют на изменение.
| (Обратите внимание, как другие элементы в списке перемещаются вниз в ответ на рост одного элемента) |
---|---|