如需自定义共享元素转换动画的运行方式,您可以使用一些参数来更改共享元素的转换方式。
动画规范
如需更改用于尺寸和位置移动的动画规范,您可以在 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
规范。
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 )
如果您需要确保共享元素永远不会在父容器之外呈现,可以在 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
。这样做会导致相应商品放大或缩小。布局中的所有其他项都会响应此更改。
|
(请注意,列表中的其他项如何因其中一项变大而向下移动) |
---|---|