效果:
直接上完整代码
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun TestBottom(musicViewModel: MusicViewModel = hiltViewModel()) {
val musicName = remember { mutableStateOf("依旧范特西依旧范特西依旧范特西依旧范特西依旧范特西") }
Row(
modifier = Modifier
.navigationBarsPadding()
.padding(
start = MediumDimen,
end = MediumDimen,
bottom = MediumDimen,
top = SmallDimen
)
.shadow(4.dp, RoundedCornerShape(20.dp))
.background(CardBackgroundColor)
.wrapContentWidth(),
verticalAlignment = Alignment.CenterVertically
) {
MusicImageAndProgress()
AnimatedContent(
targetState = musicViewModel.isPlaying,
transitionSpec = {
slideInVertically(animationSpec = tween(250, 250)) with
slideOutVertically(animationSpec = tween(250)) using
SizeTransform { initialSize, targetSize ->
if (targetState) {
keyframes {
// Expand horizontally first.
IntSize(targetSize.width, initialSize.height) at 300
durationMillis = 400
}
} else {
keyframes {
// Shrink vertically first.
IntSize(initialSize.width, targetSize.height) at 300
durationMillis = 400
}
}
}
}, contentAlignment = Alignment.Center
) { targetExpanded ->
Row(verticalAlignment = Alignment.CenterVertically) {
if (targetExpanded) {
Column(
modifier = Modifier
.weight(2f)
.padding(4.dp),
verticalArrangement = Arrangement.Center
) {
Text(
text = musicName.value,
fontSize = 14.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(text = "mood", fontSize = 12.sp)
}
Icon(
modifier = Modifier
.size(42.dp)
.clickable {
musicViewModel.pauseOrRestoreMusic()
},
imageVector = if (musicViewModel.isPlaying) Icons.Filled.PauseCircleOutline
else Icons.Filled.PlayCircleOutline,
tint = ImagePinkColor,
contentDescription = stringResource(id = R.string.music)
)
}
}
}
}
}
要点是AnimatedContent里的transitionSpec参数
transitionSpec = {
//tween 第一个参数在持续时间内完成动画,第二个延迟执行
//with 将两个动画组成 ContentTransform,它定义了内容如何进入和退出
//using 自定义给定ContentTransform的SizeTransform ,它定义了当内容的大小发生变化时如何从一种大小转换为另一种大小
slideInVertically(animationSpec = tween(250, 250)) with
slideOutVertically(animationSpec = tween(250)) using
SizeTransform { initialSize, targetSize ->
if (targetState) {
//创建一个KeyframesSpec动画,根据动画持续时间中不同时间戳(即不同关键帧)定义的值进行动画处理
keyframes {
// Expand horizontally first.
//at用来让动画在规定时间在这个值,也就是在300毫秒时应该达到这个大小
IntSize(targetSize.width, initialSize.height) at 300
//字面意思,持续时间
durationMillis = 400
}
} else {
keyframes {
// Shrink vertically first.
IntSize(initialSize.width, targetSize.height) at 300
durationMillis = 400
}
}
}
}
更多动画请到动画 | Jetpack Compose | Android Developers (google.cn)学习,compose动画实现十分方便。