使用 Jetpack Compose 制作动画形状 Android
Animate shape using Jetpack compose for Android
我想使用 compose like stock Android 12 像这样构建一个很棒的锁屏:
我设法做了类似的事情,但是我有 2 个问题,一个是当我使用 pointerInteropFilter
获取动作事件时我使用 remember
值来改变形状,return 在这个函数中我得到了一个类似的动画,但是点击监听器没有被调用,如果我 return 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()
}
}
}
这是我的结果
Syntax
Description
Motion event true
Motion event false
为了设置半径动画,您需要使用 animate*AsState()
API 之一。
这里的关键是通过使用 animateDpAsState()
逐渐改变形状的角半径,因为圆是 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()
}
}
}
我想使用 compose like stock Android 12 像这样构建一个很棒的锁屏:
我设法做了类似的事情,但是我有 2 个问题,一个是当我使用 pointerInteropFilter
获取动作事件时我使用 remember
值来改变形状,return 在这个函数中我得到了一个类似的动画,但是点击监听器没有被调用,如果我 return 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()
}
}
}
这是我的结果
Syntax | Description |
---|---|
Motion event true | Motion event false |
为了设置半径动画,您需要使用 animate*AsState()
API 之一。
这里的关键是通过使用 animateDpAsState()
逐渐改变形状的角半径,因为圆是 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()
}
}
}