如何在Jetpack Compose中点击TextButton时显示动画并修改Icon颜色
问题描述
我有如下ButtonBar Composable组件代码:
@Composable fun ButtonBar(items: List<ActionButtons>) { AppTheme { LazyRow( contentPadding = PaddingValues(horizontal = 8.dp), ) { items(items) { Box() { TextButton( shape = RectangleShape, onClick = { it.action }, colors = ButtonDefaults.buttonColors( contentColor = AppTheme.colors.primary, containerColor = AppTheme.colors.backgroundColor, ), ) { Icon( ImageVector.vectorResource(id = it.buttonIconRes), contentDescription = it.buttonString, modifier = Modifier.size(8.dp), tint = AppTheme.colors.primary, ) Spacer(modifier = Modifier.width(8.dp)) Text( text = it.buttonString, style = AppTheme.typography.baseTextAppearanceAction1, color = AppTheme.colors.primary, ) } if (it.buttonOnClickAnim != null) { val composition by rememberLottieComposition( spec = LottieCompositionSpec.RawRes(resId = it.buttonOnClickAnim), ) LottieAnimation( composition = composition, modifier = Modifier.align(Alignment.CenterStart).padding(start = 12.dp), iterations = it.animRepeatCount, ) } } } } } }
我希望实现:当用户点击TextButton时,才显示LottieAnimation,同时将Icon的tint改为透明。
在传统XML视图中,我可以通过id获取视图并在onClick中修改,示例代码如下:
buttonItem.buttonOnClickAnim?.let { itemBinding.anim.repeatCount = buttonItem.animRepeatCount itemBinding.anim.setAnimation(it) } itemBinding.actionBarButtonText.setOnClickListener { if (buttonItem.buttonOnClickAnim != null) { itemBinding.anim.isVisible = true itemBinding.actionBarButtonText.drawableStart?.setTint(itemView.context.getColor(R.color.transparent)) } buttonItem.action.invoke() }
请问在Jetpack Compose中如何实现类似效果?
解决方案
Jetpack Compose是声明式UI框架,无法直接通过id获取视图修改属性,需通过状态驱动UI变化。为每个按钮维护独立的点击状态,根据状态控制动画可见性和图标颜色即可实现需求:
修改后的完整代码如下:
@Composable fun ButtonBar(items: List<ActionButtons>) { AppTheme { LazyRow( contentPadding = PaddingValues(horizontal = 8.dp), ) { items(items) { buttonItem -> // 为每个按钮独立维护点击状态 val isClicked = remember { mutableStateOf(false) } Box() { TextButton( shape = RectangleShape, onClick = { // 更新点击状态 isClicked.value = true // 执行原有点击逻辑 buttonItem.action.invoke() }, colors = ButtonDefaults.buttonColors( contentColor = AppTheme.colors.primary, containerColor = AppTheme.colors.backgroundColor, ), ) { Icon( ImageVector.vectorResource(id = buttonItem.buttonIconRes), contentDescription = buttonItem.buttonString, modifier = Modifier.size(8.dp), // 根据点击状态切换图标颜色:点击后设为透明 tint = if (isClicked.value) Color.Transparent else AppTheme.colors.primary, ) Spacer(modifier = Modifier.width(8.dp)) Text( text = buttonItem.buttonString, style = AppTheme.typography.baseTextAppearanceAction1, color = AppTheme.colors.primary, ) } buttonItem.buttonOnClickAnim?.let { animRes -> val composition by rememberLottieComposition( spec = LottieCompositionSpec.RawRes(resId = animRes), ) // 绑定动画播放状态:点击后开始播放 val progress by animateLottieCompositionAsState( composition = composition, iterations = buttonItem.animRepeatCount, isPlaying = isClicked.value, ) LottieAnimation( composition = composition, progress = { progress }, modifier = Modifier .align(Alignment.CenterStart) .padding(start = 12.dp) // 根据点击状态控制动画可见性 .alpha(if (isClicked.value) 1f else 0f), iterations = buttonItem.animRepeatCount, ) } } } } } }
关键改动说明:
- 独立状态维护:用
remember { mutableStateOf(false) }为每个按钮创建专属的点击状态,Compose会自动监听状态变化并触发UI重组。 - 图标颜色控制:在
Icon的tint参数中根据isClicked.value切换颜色,点击后直接设为透明。 - 动画控制:
- 通过
animateLottieCompositionAsState绑定播放状态,当isClicked.value为true时自动开始播放动画。 - 用
Modifier.alpha()控制动画可见性,未点击时设为0(完全透明隐藏),点击后设为1(正常显示)。
- 通过
- 点击逻辑同步:在
onClick中先更新状态,再执行原有业务逻辑,确保UI状态与操作同步。
如果需要动画播放完毕后重置状态(允许再次点击触发动画),可以监听动画进度,在播放完成时重置状态,示例代码如下:
LaunchedEffect(progress) { // 仅当动画播放完成且是单次播放时重置状态 if (progress == 1f && buttonItem.animRepeatCount == 1) { isClicked.value = false } }
内容的提问来源于stack exchange,提问作者kk_1807
相关产品推荐
相关产品推荐

