You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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切换颜色,点击后直接设为透明。
  • 动画控制:
    1. 通过animateLottieCompositionAsState绑定播放状态,当isClicked.value为true时自动开始播放动画。
    2. 用Modifier.alpha()控制动画可见性,未点击时设为0(完全透明隐藏),点击后设为1(正常显示)。
  • 点击逻辑同步:在onClick中先更新状态,再执行原有业务逻辑,确保UI状态与操作同步。

如果需要动画播放完毕后重置状态(允许再次点击触发动画),可以监听动画进度,在播放完成时重置状态,示例代码如下:

LaunchedEffect(progress) {
    // 仅当动画播放完成且是单次播放时重置状态
    if (progress == 1f && buttonItem.animRepeatCount == 1) {
        isClicked.value = false
    }
}

内容的提问来源于stack exchange,提问作者kk_1807

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 13:55:15