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

如何在Jetpack Compose中实现布尔值变化时的抖动动画?

在Jetpack Compose中触发状态变化时实现抖动动画

你可以通过关键帧动画或手动控制动画序列实现需求——不需要改变最终状态,仅在布尔值触发时让元素完成一次抖动后回到原位。以下是两种可行方案:

方案一:使用animateFloatAsState配合关键帧

利用keyframes动画规范,让动画的起始和结束值均为0,但在中间时间点设置偏移量,从而产生抖动效果。

@Composable
fun ShakeAnimationDemo() {
    var text by remember { mutableStateOf("") }
    var isError by remember { mutableStateOf(false) }

    // 抖动偏移量:起始和结束都是0,中间通过关键帧实现左右晃动
    val shakeOffset by animateFloatAsState(
        targetValue = 0f, // 始终以0为目标值
        animationSpec = keyframes {
            durationMillis = 500 // 抖动总时长
            10f at 100ms   // 100ms时向右偏移10dp
            -10f at 200ms  // 200ms时向左偏移10dp
            8f at 300ms    // 300ms时向右偏移8dp
            -5f at 400ms   // 400ms时向左偏移5dp
            0f at 500ms    // 500ms时回到原位
        },
        // 动画结束后重置状态,确保下次触发有效
        finishedListener = { isError = false }
    )

    Column(modifier = Modifier.padding(16.dp)) {
        TextField(
            value = text,
            onValueChange = { text = it },
            label = { Text("输入内容") },
            modifier = Modifier
                .offset(x = shakeOffset.dp) // 将偏移量转为dp单位
                .fillMaxWidth()
        )

        Button(
            onClick = { isError = true }, // 触发抖动
            modifier = Modifier.padding(top = 16.dp)
        ) {
            Text("触发抖动")
        }
    }
}

方案二:使用Animatable手动控制动画序列

通过Animatable连续执行多个小动画,手动控制每一次的偏移和时长,灵活性更高。

@Composable
fun ManualShakeDemo() {
    var text by remember { mutableStateOf("") }
    var isError by remember { mutableStateOf(false) }
    val shakeAnimatable = remember { Animatable(0f) }

    // 当isError状态变化时启动动画序列
    LaunchedEffect(isError) {
        if (isError) {
            // 依次执行偏移动画,模拟抖动
            shakeAnimatable.animateTo(10f, animationSpec = tween(100))
            shakeAnimatable.animateTo(-10f, animationSpec = tween(100))
            shakeAnimatable.animateTo(8f, animationSpec = tween(100))
            shakeAnimatable.animateTo(-5f, animationSpec = tween(100))
            shakeAnimatable.animateTo(0f, animationSpec = tween(100))
            // 动画结束后重置状态
            isError = false
        }
    }

    Column(modifier = Modifier.padding(16.dp)) {
        TextField(
            value = text,
            onValueChange = { text = it },
            label = { Text("输入内容") },
            modifier = Modifier
                .offset(x = shakeAnimatable.value.dp)
                .fillMaxWidth()
        )

        Button(
            onClick = { isError = true },
            modifier = Modifier.padding(top = 16.dp)
        ) {
            Text("触发抖动")
        }
    }
}

注意事项

  • 两种方案都需要在动画结束后重置isError状态,否则再次触发时因为状态未变化,动画不会重新执行。
  • 可以调整关键帧的durationMillis、偏移量数值或tween的时长,来控制抖动的幅度、频率和整体节奏。
  • 偏移量使用dp单位是为了适配不同屏幕,避免在高分辨率设备上抖动效果不明显。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 09:25:44