Чтобы настроить анимацию перехода общих элементов, можно использовать несколько параметров, которые изменяют способ перехода общих элементов.
Спецификация анимации
Чтобы изменить спецификацию анимации, используемую для изменения размера и положения, можно указать другой параметр boundsTransform
в Rect
Modifier.sharedElement()
. Это задаст начальное и конечное положение объекта 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
.
boundsTransform
Режим изменения размера
При анимации между двумя общими границами можно задать параметр resizeMode
равным RemeasureToBounds
или ScaleToBounds
. Этот параметр определяет, как общий элемент переходит между двумя состояниями. ScaleToBounds
сначала измеряет дочерний макет с помощью ограничений, заданных в прогнозируемом (или целевом) виде. Затем стабильный макет дочернего элемента масштабируется, чтобы уместиться в общих границах. ScaleToBounds
можно рассматривать как «графическую шкалу» между состояниями.
В отличие от этого, RemeasureToBounds
перемеряет и перерисовывает дочерний макет sharedBounds
с анимированными фиксированными ограничениями на основе целевого размера. Переизмерение запускается при изменении размера границ, что потенциально может происходить в каждом кадре.
Для Text
компонуемых элементов рекомендуется использовать ScaleToBounds
, так как это позволяет избежать перекомпоновки и переформатирования текста на разные строки. RemeasureToBounds
рекомендуется использовать для границ с разными соотношениями сторон, а также если требуется плавная связь между двумя общими элементами.
Разницу между двумя режимами изменения размера можно увидеть в следующих примерах:
| |
---|---|
Перейти к окончательному макету
По умолчанию при переходе между двумя макетами размер макета анимируется от начального до конечного состояния. Это может быть нежелательным при анимации такого контента, как текст.
В следующем примере показано, как текст описания «Lorem Ipsum» попадает на экран двумя способами. В первом примере текст перестраивается по мере увеличения размера контейнера. Во втором примере перестраивается по мере увеличения размера. Добавление Modifier.skipToLookaheadSize()
предотвращает перестроение по мере увеличения размера.
Нет | |
---|---|
Клип и накладки
Чтобы общие элементы могли совместно использоваться разными компонуемыми объектами, рендеринг компонуемого объекта поднимается до уровня наложения слоёв при начале перехода к его соответствующему объекту в целевом объекте. Это позволяет избежать ограничений родительского объекта и его преобразований слоёв (например, альфа-канала и масштаба).
Он будет отображаться поверх других необщих элементов пользовательского интерфейса. После завершения перехода элемент будет перемещен из области наложения в свою собственную 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
. Это приведет к увеличению или уменьшению размера элемента. Все остальные элементы макета отреагируют на это изменение.
| (Обратите внимание, как другие элементы в списке перемещаются вниз в ответ на рост одного элемента) |
---|---|