Prerequisites:
- Basic knowledge of Kotlin
- Basic Knowledge of Jetpack Compose
In this article, we will take a look at how to create a bounce animation when the user taps anything, further it can be extended as per the use of the App. Here’s a sample gif demonstrating the animation.
Step by Step Implementation
Step 1: Create a New Project (Or use it in the existing Compose project)
To create a new project in the Android Studio Canary version, refer to the article How to Create a new Project in the Android Studio Canary Version with Jetpack Compose.
Step 2: Working with the MainActivity.kt
Create an enum class that stores the states (Released / Pressed).
enum class BounceState { Pressed, Released }
|
Step 3: Adding Animation
Create a composable function Bounce, add the following code
var currentState: BounceState by remember { mutableStateOf(BounceState.Released) } val transition = updateTransition(targetState = currentState, label = "animation" )
val scale: Float by transition.animateFloat( transitionSpec = { spring(stiffness = 900f) }, label = ""
) { state -> // When the item is pressed , reduce
// its size by 5% or make its size 0.95
// of its original size
// Change this value to see effect
if (state == BounceState.Pressed) {
0 .95f
} else {
// When the item is released ,
// make it of its original size
1f
}
} |
Then use the pointerInputScope modifier to detect gestures and apply the animation, add the following code to the Bounce composable as well.
// Basic compose Box Layout Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Column(modifier = Modifier .pointerInput(Unit) {
detectTapGestures(onPress = {
// Set the currentState to Pressed
// to trigger Pressed animation
currentState = BounceState.Pressed
// Waits for the tap to release
// before returning the call
tryAwaitRelease()
// Set the currentState to Release
// to trigger Release animation
currentState = BounceState.Released
})
}) {
Image(
painter = painterResource(id = R.drawable.gfg),
contentDescription = "gfg" ,
modifier = Modifier.graphicsLayer {
scaleX = scale
scaleY = scale
})
}
} |
And we are done. This is the final code for MainActivity.kt file.
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.core.Transition
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.updateTransition
import androidx.compose.foundation.Image
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import com.shaun.bounceanimation.ui.theme.BounceAnimationTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super .onCreate(savedInstanceState)
setContent {
BounceAnimationTheme {
Surface(color = MaterialTheme.colors.background) {
Bounce()
}
}
}
}
} enum class BounceState { Pressed, Released }
@Preview (showBackground = true )
@Composable fun Bounce() { var currentState: BounceState by remember { mutableStateOf(BounceState.Released) }
val transition = updateTransition(targetState = currentState, label = "animation" )
val scale: Float by transition.animateFloat(
transitionSpec = { spring(stiffness = 900f) }, label = ""
) { state ->
// When the item is pressed ,reduce its size
// by 5% or make its size 0.95 of its original size
// Change this value to see effect
if (state == BounceState.Pressed) {
0 .95f
} else {
// When the item is released ,
// make it of its original size
1f
}
}
// Basic compose Box Layout Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Column(modifier = Modifier .pointerInput(Unit) {
detectTapGestures(onPress = {
// Set the currentState to Pressed
// to trigger Pressed animation
currentState = BounceState.Pressed
// Waits for the tap to release
// before returning the call
tryAwaitRelease()
// Set the currentState to Release
// to trigger Release animation
currentState = BounceState.Released
})
}) {
Image(
painter = painterResource(id = R.drawable.gfg),
contentDescription = "gfg" ,
modifier = Modifier.graphicsLayer {
scaleX = scale
scaleY = scale
})
}
}
} |
Output:
Get the complete project from here.