Zhelyazko Atanasov
05/24/2021, 2:41 PMTextField
and a button. When the user clicks the button, if the value in the TextField
is not correct or empty, I'd like to move the TextField
to the left/right a few times to draw the user's attention. In a View
world I can do something like this:
ObjectAnimator
.ofFloat(myTextInput, "translationX", 0, 25, -25, 25, -25,15, -15, 6, -6, 0)
.setDuration(duration)
.start();
But with Compose I can't figure out a way to have the current and target value be the same.
The direction I went into is to use animateDpAsState
together with keyframes
animation spec to animate the offset
of my TextField
and it does the job. My issue is how to trigger the animation.Zhelyazko Atanasov
05/24/2021, 2:44 PMtargetValue
is 1dp in the error case (so that the animation can start). And then when the animation completes and I reset invalidInput
trigger, the animation plays again (that's another thing that I have to figure out how to tackle).
var invalidInput by remember { mutableStateOf(false) }
val offset: Dp by animateDpAsState(
targetValue = if (invalidInput) 1.dp else 0.dp,
animationSpec = keyframes {
durationMillis = 500
16.dp at 30
(-16).dp at 60
16.dp at 90
(-16).dp at 140
8.dp at 200
(-8).dp at 260
4.dp at 330
(-4).dp at 400
},
finishedListener = {
invalidInput = false
}
)
Zach Klippenstein (he/him) [MOD]
05/24/2021, 2:51 PMZach Klippenstein (he/him) [MOD]
05/24/2021, 2:52 PMZhelyazko Atanasov
05/24/2021, 3:07 PManimateTo
that I assume would require a value different from the current one. Something else that I could do is to chain 2 animations one after the other where the first one has target value set to one of the keyframes. The second animation could then animate back to 0 offset. But there has to be a simpler, more elegant solution.Zach Klippenstein (he/him) [MOD]
05/24/2021, 3:23 PMval scope = rememberCoroutineScope()
val offset = remember { Animatable(0f) }
Box(Modifier.fillMaxSize()) {
Button(
onClick = {
scope.launch {
offset.animateTo(0f, animationSpec = keyframes {
durationMillis = 500
16f at 30
(-16f) at 60
16f at 90
(-16f) at 140
8f at 200
(-8f) at 260
4f at 330
(-4f) at 400
})
}
},
modifier = Modifier.offset { IntOffset(x = offset.value.dp.roundToPx(), y = 0) }
) {
Text("shake me")
}
}
Zach Klippenstein (he/him) [MOD]
05/24/2021, 3:24 PMgraphicsLayer
since that doesn’t involve triggering another layoutZach Klippenstein (he/him) [MOD]
05/24/2021, 3:26 PMModifier.graphicsLayer { translationX = offset.value.dp.toPx() }
Zhelyazko Atanasov
05/24/2021, 3:27 PMgraphicsLayer
- I was thinking the same. I just wanted to play around and see if/how to accomplish the desired effect before polishing and optimizing it.