Open In App

Create Bounce Animation on Touch in Android Jetpack Compose

Prerequisites:

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.

 


Article Tags :