shared element是指在场景转换中,两个不同的组件拥有相同的transitionName,这样在转场过程中就可以以动画的方式平滑地从一个组件转到另一个组件。在android jetpack compose中,可以通过使用rememberUpdatedState和Transition来实现shared element的效果。示例如下:
@Composable
fun SharedElementExample(photo: Photo) {
val photoUrl by rememberUpdatedState(newValue = photo.url)
val transition = updateTransition(targetState = photo)
val imageScale: Float by transition.animateFloat(
transitionSpec = {
tween(durationMillis = 500)
}
) { photo ->
if (photo == null) 0.5f else 1f
}
val cardElevation: Dp by transition.animateDp(
transitionSpec = {
spring(stiffness = Spring.StiffnessLow)
}
) { photo ->
if (photo == null) 0.dp else 2.dp
}
Column(
modifier = Modifier
.fillMaxWidth()
.clickable { } // Navigate to detail screen
) {
Box(
modifier = Modifier
.fillMaxWidth()
.preferredHeight(240.dp)
.clip(shape = RoundedCornerShape(8.dp))
.zIndex(1f - imageScale)
.background(Color.Gray)
) {
Image(
painter = rememberCoilPainter(request = photoUrl),
contentDescription = null,
modifier = Modifier.fillMaxSize()
)
}
Spacer(modifier = Modifier.height(16.dp))
Text(
text = photo.title,
style = MaterialTheme.typography.subtitle1,
modifier = Modifier.padding(start = 16.dp, end = 16.dp)
)
Text(
text = "By ${photo.author}",
style = MaterialTheme.typography.caption,
modifier = Modifier.padding(horizontal = 16.dp)
)
Spacer(modifier = Modifier.height(16.dp))
Card(
elevation = cardElevation,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
) {
Column(
modifier = Modifier.padding(16.dp)
) {
Text(
text = photo.description,
style = MaterialTheme.typography.body1,
modifier = Modifier.fillMaxWidth()
)
}
}
}
}
在代码中,通过rememberUpdatedState来获得组件的当前状态,并使用updateTransition来创建一个transition对象,从而实现动画效果。animateFloat和animateDp则用于定义组件的scale和elevation等属性的变化过程,从而实现平滑的转场效果。