Compose 中的弹跳按钮动画

问题描述 投票:0回答:2

我想在 Compose 中制作一个这样的按钮: https://pub.dev/packages/flutter_bounceable

但是可点击的方法在我的代码中不起作用。

我尝试使用此代码,但有错误。 按下按钮,但没有任何动作。 动画效果很好,但不适用于可点击。

fun Modifier.bounceClick(onClick: () -> Unit,animationDuration: Int = 100,
                         scaleDown: Float = 0.9f) = composed {
    val interactionSource = MutableInteractionSource()

    val coroutineScope = rememberCoroutineScope()

    val scale = remember {
        Animatable(1f)
    }

    this
        .scale(scale = scale.value)
        .background(
            color = Color(0xFF35898F),
            shape = RoundedCornerShape(size = 12f)
        )
        .clickable(interactionSource = interactionSource, indication = null, onClick = onClick)
        .pointerInput(Unit) {
            while(true)
                awaitPointerEventScope {
                        awaitFirstDown()
                        coroutineScope.launch {
                            scale.animateTo(
                                scaleDown,
                                animationSpec = tween(animationDuration),
                            )
                        }
                        waitForUpOrCancellation()
                        coroutineScope.launch {
                            scale.animateTo(
                                scaleDown,
                                animationSpec = tween(20),
                            )
                            scale.animateTo(
                                1f,
                                animationSpec = tween(animationDuration),
                            )
                    }
            }
        }
}
android button android-jetpack-compose bounce android-jetpack-compose-gesture
2个回答
3
投票

使用 Compose 可以非常简单地做到这一点。

如果 Compose 版本为 1.4.0-alpha03,则应使用 foreachGesture 或 waitEachGesture 并使用 Modifier.pointerInput 而不是 while。另外,当你有可点击的功能时,你也不需要 Modifier.pointerInput ,你可以使用它们中的任何一个。

我只会演示如何使用

Modifier.clickable
interactionSource.collectIsPressedAsState()
进行操作,如下所示。

结果

实施

fun Modifier.bounceClick(
    animationDuration: Int = 100,
    scaleDown: Float = 0.9f,
    onClick: () -> Unit
) = composed {

    val interactionSource = remember { MutableInteractionSource() }
    val isPressed by interactionSource.collectIsPressedAsState()

    val animatable = remember {
        Animatable(1f)
    }

    LaunchedEffect(key1 = isPressed) {
        if (isPressed) {
            animatable.animateTo(scaleDown)
        } else animatable.animateTo(1f)
    }

    Modifier
        .graphicsLayer {
            val scale = animatable.value
            scaleX = scale
            scaleY = scale
        }
        .clickable(
            interactionSource = interactionSource,
            indication = null
        ) {
            onClick()
        }
}

使用方法

@Composable
private fun BounceExample() {
    Row {
        Box(
            Modifier

                .background(Color.Red, RoundedCornerShape(10.dp))
                .bounceClick {

                }
                .padding(10.dp),
            contentAlignment = Alignment.Center
        ) {
            Text(text = "Hello World", color = Color.White, fontSize = 20.sp)
        }
        Spacer(modifier = Modifier.width(10.dp))

        Box(
            Modifier

                .bounceClick {

                }
                .background(Color.Green, RoundedCornerShape(10.dp))
                .padding(10.dp),
            contentAlignment = Alignment.Center
        ) {
            Text(text = "Hello World", color = Color.White, fontSize = 20.sp)
        }
    }
}

0
投票

@Thracian 的回答有一个小问题。如果按钮位于可滚动容器中,并且您快速点击按钮,它将不会产生动画效果。这是因为 isPressed 状态由于内置延迟而不会调度(位于

Clickable.kt
撰写文件中)。

要修复它,请将其更改为以下内容:

private fun Modifier.bounceClick(
    scaleDown: Float = 0.90f,
    onClick: () -> Unit
) = composed {

    val interactionSource = remember { MutableInteractionSource() }

    val animatable = remember {
        Animatable(1f)
    }

    LaunchedEffect(interactionSource) {
        interactionSource.interactions.collect { interaction ->
            when (interaction) {
                is PressInteraction.Press -> animatable.animateTo(scaleDown)
                is PressInteraction.Release -> animatable.animateTo(1f)
                is PressInteraction.Cancel -> animatable.animateTo(1f)
            }
        }
    }

    Modifier
        .graphicsLayer {
            val scale = animatable.value
            scaleX = scale
            scaleY = scale
        }
        .clickable(
            interactionSource = interactionSource,
            indication = null
        ) {
            onClick()
        }
}
© www.soinside.com 2019 - 2024. All rights reserved.