我想用 Jetpack Compose 从 AirBnB 应用程序中创建这个很棒的按钮动画
不幸的是,动画/过渡 API 最近发生了变化,而且几乎没有相关文档。有人可以帮我找到实现此按钮按下动画的正确方法吗?
编辑 根据@Amirhosein 的回答,我开发了一个按钮,看起来几乎与 Airbnb 示例一模一样
代码:
@Composable
fun AnimatedButton() {
val boxHeight = animatedFloat(initVal = 50f)
val relBoxWidth = animatedFloat(initVal = 1.0f)
val fontSize = animatedFloat(initVal = 16f)
fun animateDimensions() {
boxHeight.animateTo(45f)
relBoxWidth.animateTo(0.95f)
// fontSize.animateTo(14f)
}
fun reverseAnimation() {
boxHeight.animateTo(50f)
relBoxWidth.animateTo(1.0f)
//fontSize.animateTo(16f)
}
Box(
modifier = Modifier
.height(boxHeight.value.dp)
.fillMaxWidth(fraction = relBoxWidth.value)
.clip(RoundedCornerShape(8.dp))
.background(Color.Black)
.clickable { }
.pressIndicatorGestureFilter(
onStart = {
animateDimensions()
},
onStop = {
reverseAnimation()
},
onCancel = {
reverseAnimation()
}
),
contentAlignment = Alignment.Center
) {
Text(text = "Explore Airbnb", fontSize = fontSize.value.sp, color = Color.White)
}
}
视频:
不幸的是,我无法弄清楚如何正确地为文本设置动画,因为它目前看起来很糟糕
答案 0 :(得分:3)
使用 pressIndicatorGestureFilter
实现此行为。
这是我的解决方法:
@Preview
@Composable
fun MyFancyButton() {
val boxHeight = animatedFloat(initVal = 60f)
val boxWidth = animatedFloat(initVal = 200f)
Box(modifier = Modifier
.height(boxHeight.value.dp)
.width(boxWidth.value.dp)
.clip(RoundedCornerShape(4.dp))
.background(Color.Black)
.clickable { }
.pressIndicatorGestureFilter(
onStart = {
boxHeight.animateTo(55f)
boxWidth.animateTo(180f)
},
onStop = {
boxHeight.animateTo(60f)
boxWidth.animateTo(200f)
},
onCancel = {
boxHeight.animateTo(60f)
boxWidth.animateTo(200f)
}
), contentAlignment = Alignment.Center) {
Text(text = "Utforska Airbnb", color = Color.White)
}
}
默认的 jetpack compose Button
在其 onClick
事件中使用点击手势,而 pressIndicatorGestureFilter
不接收点击。这就是我创建这个自定义按钮的原因
答案 1 :(得分:2)
你在寻找这样的东西吗?
@Composable
fun AnimatedButton() {
val selected = remember { mutableStateOf(false) }
val scale = animateFloatAsState(if (selected.value) 2f else 1f)
Column(
Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Button(
onClick = { },
modifier = Modifier
.scale(scale.value)
.height(40.dp)
.width(200.dp)
.pointerInteropFilter {
when (it.action) {
MotionEvent.ACTION_DOWN -> {
selected.value = true }
MotionEvent.ACTION_UP -> {
selected.value = false }
}
true
}
) {
Text(text = "Explore Airbnb", fontSize = 15.sp, color = Color.White)
}
}
}
答案 2 :(得分:1)
通过 1.0.0-beta06
,您可以使用 Modifier.pointerInput
来检测 tapGesture。
定义一个枚举:
enum class ComponentState { Pressed, Released }
那么:
var toState by remember { mutableStateOf(ComponentState.Released) }
val modifier = Modifier.pointerInput(Unit) {
detectTapGestures(
onPress = {
toState = ComponentState.Pressed
tryAwaitRelease()
toState = ComponentState.Released
}
)
}
// Defines a transition of `ComponentState`, and updates the transition when the provided [targetState] changes
val transition: Transition<ComponentState> = updateTransition(targetState = toState, label = "")
// Defines a float animation to scale x,y
val scalex: Float by transition.animateFloat(
transitionSpec = { spring(stiffness = 50f) }, label = ""
) { state ->
if (state == ComponentState.Pressed) 1.25f else 1f
}
val scaley: Float by transition.animateFloat(
transitionSpec = { spring(stiffness = 50f) }, label = ""
) { state ->
if (state == ComponentState.Pressed) 1.05f else 1f
}
应用 modifier
并使用 Modifier.graphicsLayer
还可以更改文本尺寸。
Box(
modifier
.padding(16.dp)
.width((100 * scalex).dp)
.height((50 * scaley).dp)
.background(Color.Black, shape = RoundedCornerShape(8.dp)),
contentAlignment = Alignment.Center) {
Text("BUTTON", color = Color.White,
modifier = Modifier.graphicsLayer{
scaleX = scalex;
scaleY = scaley
})
}
答案 3 :(得分:0)
如果你想用不同类型的动画制作按钮动画,比如缩放、旋转和许多不同类型的动画,那么你可以在 jetpack compose 中使用这个库。 Check Here