如需自定义共享元素过渡动画的运行方式,可使用一些 可用于更改共享元素的转换方式的参数。
动画规范
如需更改用于大小和位置移动的动画规范,您可以在 Modifier.sharedElement()
上指定不同的 boundsTransform
参数。这会提供初始 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 中创建共享元素时的一个重要概念是, 以便在不同的可组合项之间共享, 可组合项提升为层叠加层, 其匹配项在目标位置中的匹配项。这样做的效果是,它会逃出父级的边界及其图层转换(例如 alpha 和缩放)。
它将在其他非共享界面元素之上呈现,过渡完成后,该元素将从叠加层移至自己的 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 )
如果您需要确保共享元素绝不会在父元素之外呈现
容器,可以在 sharedElement()
上设置 clipInOverlayDuringTransition
。修改者
默认情况下,对于嵌套的共享边界,clipInOverlayDuringTransition
会使用裁剪
从父级 sharedBounds()
开始。
支持保留特定的界面元素,例如底部栏或悬浮操作
按钮,在共享元素转换期间始终位于顶部,使用
Modifier.renderInSharedTransitionScopeOverlay()
。默认情况下,
修饰符会将内容保留在叠加层中
是否处于活动状态。
例如,在 Jetsnack 中,BottomAppBar
需要放在共享元素之上,直到屏幕不可见为止。添加修饰符
添加到可组合项上可使其保持提升状态。
不含 |
使用 |
---|---|
有时,您可能希望非共享可组合项在转换前以动画效果消失,同时保持在其他可组合项之上。在这种情况下,请在共享元素转换运行时使用 renderInSharedTransitionScopeOverlay().animateEnterExit()
为可组合项添加动画效果:
JetsnackBottomBar( modifier = Modifier .renderInSharedTransitionScopeOverlay( zIndexInOverlay = 1f, ) .animateEnterExit( enter = fadeIn() + slideInVertically { it }, exit = fadeOut() + slideOutVertically { it } ) )
在极少数情况下,如果您希望共享元素不渲染在叠加层中,可以将 sharedElement()
上的 renderInOverlayDuringTransition
设置为 false。
在共享元素大小更改时通知同级布局
默认情况下,sharedBounds()
和 sharedElement()
不会通知父级
任何尺寸的容器会随着布局转换而发生变化
为了在父级容器转换时将大小更改传播到父级容器,请将 placeHolderSize
参数更改为 PlaceHolderSize.animatedSize
。这样做会导致项放大或缩小。布局中的所有其他项都会响应此更改。
|
(请注意,列表中的其他项如何随着某个项的增大而向下移动) |
---|---|