使用适用于 Android 的 Jetpack compose 制作形状动画

Jav*_*ier 6 android android-animation android-jetpack-compose

我想使用像 Android 12 这样的 compose 构建一个很棒的锁屏,如下所示:

我设法做了类似的事情,但是我有两个问题,一个是当我用来pointerInteropFilter获取动作事件时,我使用一个remember值来改变形状,在这个函数中返回 true 我得到了一个类似的动画,但是点击监听器没有被调用,如果我返回false形状保持“方形”,我缺少什么?有什么方法可以使“形状”动起来吗?我找到了 DP、颜色和尺寸,但没有找到形状。这是代码

@Composable
fun RoundedPinBackground(
    modifier: Modifier = Modifier,
    backgroundColor: Color,
    onClicked: () -> Unit,
    content: @Composable () -> Unit,
) {
    var selected by remember { mutableStateOf(false) }

    val shape = if (selected) {
        RoundedCornerShape(10.dp)
    } else {
        CircleShape
    }
    Surface(
        tonalElevation = 10.dp,
        modifier = Modifier
            .clip(shape)
    ) {
        Box(modifier = modifier
            .size(80.dp)
            .clip(shape)
            .background(color = backgroundColor)
            .clickable { onClicked.invoke() }
            .pointerInteropFilter {
                when (it.action) {
                    MotionEvent.ACTION_DOWN -> {
                        selected = true
                    }

                    MotionEvent.ACTION_UP -> {
                        selected = false
                    }
                }
                true
            },
            contentAlignment = Alignment.Center
        ) {
            content()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的结果

句法 描述
运动事件 true 运动事件 false
运动事件返回 true,但没有波纹或点击 运动事件返回 false 但保持方形

rig*_*roo 9

为了对半径进行动画处理,您需要使用animate*AsState()API 之一。

这里的关键是使用 逐渐改变 Shape 的角半径animateDpAsState(),因为 Circle 的RoundedCornerShape角半径是整体大小的一半Circle

为了获得波纹,您可以使用可点击修饰符 与rememberRipple()作为指示。

下面是两者的工作示例:

@Composable
fun RoundedPinBackground(
    modifier: Modifier = Modifier,
    size: Dp,
    backgroundColor: Color,
    onClicked: () -> Unit,
    content: @Composable () -> Unit,
) {
    val interactionSource = remember { MutableInteractionSource() }
    val isPressed = interactionSource.collectIsPressedAsState()
    val radius = if (isPressed.value) {
        10.dp
    } else {
        size / 2f
    }
    val cornerRadius = animateDpAsState(targetValue = radius)

    Surface(
        tonalElevation = 10.dp,
        modifier = modifier
            .clip(RoundedCornerShape(cornerRadius.value))
    ) {
        Box(
            modifier = Modifier
                .background(color = backgroundColor)
                .size(size)
                .clip(RoundedCornerShape(cornerRadius.value))
                .clickable(
                    interactionSource = interactionSource,
                    indication = rememberRipple()
                ) { onClicked.invoke() },
            contentAlignment = Alignment.Center
        ) {
            content()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

具有半径和波纹的动画