Creating a wiggle animation in jetpack compose
Indicating that the user has entered the wrong input, or folk has to complete the steps on the particular screen before moving to the next step is sometimes a trivial step.
This indication is sometimes provided through haptic feedback or wiggle animation.
Let us see how we can achieve the same in Jetpack compose.
Let’s start by creating a Text to be animated.
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
Button(){
Text(text = "Animate")
}
}
Before we move any further, let’s take a second to understand how this will work. We will provide an offset to the text, and change the offset of the text on the x-axis during the animation duration. This brings us to the prerequisites that we need to have a variable offset, something to change the offset.
For having a variable offset we will use Animatable like following
val offsetX = remember { Animatable(0f) }
Text(
text = "Hello $name!",
modifier = Modifier
.offset(offsetX.value.dp, 0.dp)
)
We will then create an AnimationSpec using keyframes like following
private val shakeKeyframes: AnimationSpec<Float> = keyframes {
durationMillis = 800
val easing = FastOutLinearInEasing
// generate 8 keyframes
for (i in 1..8) {
val x = when (i % 3) {
0 -> 4f
1 -> -4f
else -> 0f
}
x at durationMillis / 10 * i with easing
}
}
Let us understand how the above snippet works.
We first define the duration of the entire animation using durationMillis
property, and we then define the Animation Curve, for this example, I am using the FastOutLinearInEasing
Curve, but if required you can use CubicBezierEasing
. You can easily generate one from Cubic-Bezier. We then define the different values of the Animation Spec. Breaking down the above for loop it would look something like this.
-4F at durationMillis / 10 * 1 with easing
0F at durationMillis / 10 * 2 with easing
4F at durationMillis / 10 * 3 with easing
-4F at durationMillis / 10 * 4 with easing
0F at durationMillis / 10 * 5 with easing
4F at durationMillis / 10 * 6 with easing
0F at durationMillis / 10 * 7 with easing
-4F at durationMillis / 10 * 8 with easing
Boom!! We have our prerequisites in place. We just need to apply the offset to our text, and then animate our offsetX
. We can do so in the following way.
Apply offset like the following. Note that we are only using the x value of offset since we need to animate it horizontally.
Text(
text = "Hello $name!",
modifier = Modifier
.offset(offsetX.value.dp, 0.dp)
)
and then create a CoroutineScope
so that we can animate offsetX
.
coroutineScope.launch {
offsetx.animateTo(
targetValue = 0f,
animationSpec = shakeKeyframes,
)
}
And since we intended to show this to warn users, let’s also add haptic in it.
Final GitHub gist with haptic feedback added.
Clap to say “thank you” and to help others find this article.
You can Follow me or reach out to me on Twitter for any queries.
You can also buy me a coffee : )
Thank you!