Spring Animations

ANIMATION

Spring Animation with kotlin in Android

A complete guide for physics based animations.

Himanshu Choudhary
3 min readApr 4, 2020

--

Spring animation Gif

Designing animations, you need to analyze their influence on usability and desirability of the app — and if you cannot see a real positive impact, reconsider the approach.

Good UI animation is always a cherry on top.

With this thought, let’s start coding.

Oh wait. If you don’t much reading there a video of this lesson at the end of this blog. You can have a look at that :)

Prerequisite :

  • You should have an idea about Data Binding and View Model.

Build.gradle (app level)

  • Enable the data binding.
android {
...

dataBinding {
enabled = true
}

}
  • Add plugin at top
apply plugin: 'kotlin-kapt'
  • Add the following dependencies
dependencies {
...

implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
implementation 'androidx.dynamicanimation:dynamicanimation:1.0.0'

}

activity_main.xml

  • Add Layout tag (Part of data binding) and floating action button.
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true">

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/ic_add_black_24dp"/>

</RelativeLayout>

</layout>

All of our code logic will be in a view model.
- Create a view model — I have named it as MainActivityViewModel.

Our steps will be :

  • Animation part
  1. To create a spring animation which will be attached to the view which we want to animate.
  2. For a spring animation, there is a spring (property) which we need to define.
  3. And, In that Spring we need to specify the stiffness and the damping ratio.
  • UI part
  1. We need to attach an observer to the view which will tell us the position of that view and on the basis of that we need to update the animation attached to that view.
  2. Since we have attached an observer to the view, it also overrides the default listener provided by the android framework like onCLickListener. So, to get those working we have to create them of our own.

This sounds so much hard but believe me it is not. For now, I just want you to absorb all this to have a fair idea about how we are going to tackle the problem.

MainActivityViewModel.kt

All the following code below is the part of MainActivityViewModel.

  • Create spring animation
private fun createSpringAnimation(view: View,
property: DynamicAnimation.ViewProperty,
finalPosition: Float): SpringAnimation {
val animation = SpringAnimation(view, property)
val spring = SpringForce(finalPosition)
spring.stiffness = SpringForce.STIFFNESS_MEDIUM
spring.dampingRatio = SpringForce.DAMPING_RATIO_HIGH_BOUNCY
animation.spring = spring
return animation
}
  • Create view observer
fun setUpAnimation(view: View, callback: () -> Unit) {

lateinit var xAnimation: SpringAnimation
lateinit var yAnimation: SpringAnimation

view.viewTreeObserver.addOnGlobalLayoutListener(object: ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
xAnimation = createSpringAnimation(view, SpringAnimation.X, view.x)
yAnimation = createSpringAnimation(view, SpringAnimation.Y, view.y)
view.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
})

var dX = 0f
var dY = 0f
val gestureDetector = GestureDetector(view.context, SingleTapConfirm())

view.setOnTouchListener { _view, event ->
if(gestureDetector.onTouchEvent(event)) {
callback.invoke()
}else {
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
dX = _view.x - event.rawX
dY = _view.y - event.rawY

xAnimation.cancel()
yAnimation.cancel()
}
MotionEvent.ACTION_MOVE -> {
view.animate()
.x(event.rawX + dX)
.y(event.rawY + dY)
.setDuration(0)
.start()
}
MotionEvent.ACTION_UP -> {
xAnimation.start()
yAnimation.start()
}
}
}
true
}
}
  • Create custom OnClickListener
private class SingleTapConfirm : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapUp(event: MotionEvent): Boolean {
return true
}
}

That’s It. !!

Hard part is over. Now we just have to link our activity to our view model.

MainActivity.kt

  • Create variable for binding and view model.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
mainActivityViewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)
mainActivityViewModel.setUpAnimation(view = binding.floatingBtn, callback = {
Toast.makeText(this, "Button clicked !!", Toast.LENGTH_LONG).show()
})
}

Cheers !!

You have done a great job.

Now, run your app and check how much awesome you have created your new animation.

Treat from my side :

  1. If you want to create awesome view with much less code then do check out the links below :

2. Video of this tutorial :

3. Github code link :

I hope you this piece have helped you. If yes, please give a high five by clicking on the hands showing on your left side. Thank you :)

--

--