我正在try 制作喷气背包形状的摇晃动画.我想使用这个动画来显示错误时,用户输入无效的个人识别码.但我能找到的只有滑入、滑出的动画和一些zoom 动画.你知道我怎么才能做到这一点吗?

Update:个 在@色雷斯语回答之后.我使用如下代码,水平摇动我的物品:

fun Modifier.shake(enabled: Boolean, onAnimationFinish: () -> Unit) = composed(
    factory = {
        val distance by animateFloatAsState(
            targetValue = if (enabled) 15f else 0f,
            animationSpec = repeatable(
                iterations = 8,
                animation = tween(durationMillis = 50, easing = LinearEasing),
                repeatMode = RepeatMode.Reverse
            ),
            finishedListener = { onAnimationFinish.invoke() }
        )

        Modifier.graphicsLayer {
            translationX = if (enabled) distance else 0f
        }
    },
    inspectorInfo = debugInspectorInfo {
        name = "shake"
        properties["enabled"] = enabled
    }
)

推荐答案

enter image description here

不幸的是,GIF比实际动画慢,但它给出了一个结果的 idea .

这可以通过许多方式来实现.您应该在短时间内更改scaleX和/或scaleY才能产生抖动效果.如果要进行旋转,请更改Modifier.graph层的旋转Z

 @Composable
private fun ShakeAnimationSamples() {
    Column(modifier = Modifier
        .fillMaxSize()
        .padding(10.dp)) {

        var enabled by remember {
            mutableStateOf(false)
        }
        val scale by animateFloatAsState(
            targetValue = if (enabled) .9f else 1f,
            animationSpec = repeatable(
                iterations = 5,
                animation = tween(durationMillis = 50, easing = LinearEasing),
                repeatMode = RepeatMode.Reverse
            ),
            finishedListener = {
                enabled = false
            }
        )

        val infiniteTransition = rememberInfiniteTransition()
        val scaleInfinite by infiniteTransition.animateFloat(
            initialValue = 1f,
            targetValue = .85f,
            animationSpec = infiniteRepeatable(
                animation = tween(30, easing = LinearEasing),
                repeatMode = RepeatMode.Reverse
            )
        )

        val rotation by infiniteTransition.animateFloat(
            initialValue = -10f,
            targetValue = 10f,
            animationSpec = infiniteRepeatable(
                animation = tween(30, easing = LinearEasing),
                repeatMode = RepeatMode.Reverse
            )
        )

        Icon(
            imageVector = Icons.Default.NotificationsActive,
            contentDescription = null,
            tint = Color.White,
            modifier = Modifier
                .graphicsLayer {
                    scaleX = if (enabled) scale else 1f
                    scaleY = if (enabled) scale else 1f
                }
                .background(Color.Red, CircleShape)
                .size(50.dp)
                .padding(10.dp)
        )

        Icon(
            imageVector = Icons.Default.NotificationsActive,
            contentDescription = null,
            tint = Color.White,
            modifier = Modifier
                .graphicsLayer {
                    scaleX = scaleInfinite
                    scaleY = scaleInfinite
                    rotationZ = rotation
                }
                .background(Color.Red, CircleShape)
                .size(50.dp)
                .padding(10.dp)
        )



        Button(onClick = { enabled = !enabled }) {
            Text("Animation enabled: $enabled")
        }

    }
}

你也可以把它当作修饰语

fun Modifier.shake(enabled: Boolean) = composed(

    factory = {
        
        val scale by animateFloatAsState(
            targetValue = if (enabled) .9f else 1f,
            animationSpec = repeatable(
                iterations = 5,
                animation = tween(durationMillis = 50, easing = LinearEasing),
                repeatMode = RepeatMode.Reverse
            )
        )

        Modifier.graphicsLayer {
            scaleX = if (enabled) scale else 1f
            scaleY = if (enabled) scale else 1f
        }
    },
    inspectorInfo = debugInspectorInfo {
        name = "shake"
        properties["enabled"] = enabled
    }
)

用法

Icon(
    imageVector = Icons.Default.NotificationsActive,
    contentDescription = null,
    tint = Color.White,
    modifier = Modifier
        .shake(enabled)
        .background(Color.Red, CircleShape)
        .size(50.dp)
        .padding(10.dp)
)

Android相关问答推荐

Android可组合继承?

房间DB:UPSERT返回什么?

如何制作带有图标和文本的Fab

我如何剪裁一个可由另一个合成的

从惰性列中删除项目时Jetpack Compose崩溃

如何在Jetpack Compose中实现前后动画?

数据绑定在Android中等待填充值时显示未填充的值

为什么我收到这个错误我需要安装 android studio

Android AGP 8 + Gradle 8 + Kotlin 1.8 导致 Kapt 出错

ArrayList 上的 Android intent.getParcelableArrayListExtra 引发 Nullpointer 异常

Jetpack Compose 惰性列在单个项目更新时重新组合所有项目

为什么项目捕获对象给我在 Compose 中找不到参考

您如何衡量条形图的 4 个类别?

Jetpack compose 未解决的参考错误

如何修复 api 调用在浏览器中工作但在 android studio 中为 403

是什么让 Android Studio 中的按钮变成紫色?加上新手的其他奇怪行为

在jetpack compose中将图像添加到脚手架顶部栏

对话框中的内容不可见

更新后 Firebase 服务无法在模拟器上运行

不能在kotlin的lazycolumn中使用列表