Roughly a year ago I wrote about android physics based animation and also open sourced sample app to demonstrate its implementation. I have been maintaining that repo and made few changes since then. Lately I decided to revisit it again and try to come up with kotlin extensions for API. In this post we will see few extension functions for SpringAnimation and FlingAnimation that will make code clean and easy to understand. So let’s dive in.

Extensions for SpringAnimation

If you want to create SpringAnimation on a view property there are two ways as shown below.

val springAnimation = SpringAnimation(view, DynamicAnimation.Y)
val springAnimation = SpringAnimation(view, DynamicAnimation.Y, 0f)

Only difference between two is final position of spring. But this is however boring and we can make it more interesting using extension function so that we can express it in functional way.

fun <K> K.springAnimationOf(
    property: FloatPropertyCompat<K>,
    finalPosition: Float = Float.NaN
): SpringAnimation {
    return if (finalPosition.isNaN()) {
        SpringAnimation(this, property)
    } else {
        SpringAnimation(this, property, finalPosition)
    }
}

As you can see above extension function is on all type. So on any type you can call this function. Function takes 2 parameters, property to be animated and finalPosition which is optional in case if you want to create SpringAnimation without finalPosition as seen above. Now let’s see how you can create SpringAnimation in functional way using above extension function.

val springAnimation = view.springAnimationOf(DynamicAnimation.TRANSLATION_Y)

val springAnimation = view.springAnimationOf(DynamicAnimation.TRANSLATION_Y, 0f)

Now some of you might say you are abusing extension function because same thing can be done easily using normal constructor way and there is no point of using extension here.

Now some of you might say you are abusing extension function because same thing can be done easily using normal constructor way and there is no point of using extension here.

Initially I had same thought but if you see in terms of readability I think using extension function make sense here. Let’s move on to next extension for SpringAnimation.

If you create SpringAnimation with finalPosition, internally SpringAnimation class will create SpringForce and attach with itself. However you may want to customise or create new SpringForce (in case SpringAnimation is created without finalPosition). It would look something like this.

val springForce = SpringForce(0f)
                    .setStiffness(SpringForce.STIFFNESS_MEDIUM)
                    .setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY)

val springAnimation = SpringAnimation(view, DynamicAnimation.TRANSLATION_X).setSpring(springForce)

Let’s see extension function to simplify this.

inline fun SpringAnimation.withSpringForceProperties(func: SpringForce.() -> Unit): SpringAnimation {
  
    if (spring == null) {
        spring = SpringForce()
    }
    spring.func()
    return this
  
}

It’s an extension on SpringAnimation itself which takes another extension function on SpringForce as parameter. Since it is lambda with receiver we have access to all its private data members and methods within it. So we can access stiffness, dampingRatio and finalPosition of SpringForce within it. Notice it has null check for SpringForce in line number 3 because if your SpringAnimation is created without finalPosition then it won’t have SpringForce so it will create for you in line number 4. In line number 6 it will simply apply function on SpringForce and finally return SpringAnimation back in line number 7. Let’s see the usage.

val springAnimation = SpringAnimation(view, DynamicAnimation.TRANSLATION_X)
	.withSpringForceProperties {
		finalPosition = 0f
		stiffness = SpringForce.STIFFNESS_MEDIUM
		dampingRatio = SpringForce.DAMPING_RATIO_HIGH_BOUNCY
	}

Code is much cleaner and readable compare to one without extension function.

Extension for FlingAnimation

Creating FlingAnimation is simple and straightforward as shown below.

val flingAnimation = FlingAnimation(view, DynamicAnimation.Y)

Same as SpringAnimation we can express this in a functional way using extension function.

fun <K> K.flingAnimationOf(property: FloatPropertyCompat<K>): FlingAnimation {
    return FlingAnimation(this, property)
}

Let’s see the usage.

val flingAnimation = view.flingAnimationOf(DynamicAnimation.Y)

That’s all I have :)

All extensions we saw are going to be part of Android KTX in the future release. I will drop an update here once it is available. Meanwhile, you can find all extension functions here in my github repo. I would like to thank Jake Wharton for suggesting improvements on my initial extension functions.

Update : All the extensions in this post are now part of Android KTX for dynamic animation. Currently(While updating this note) it’s in alpha 01. Keep an eye on release notes here to keep track of future releases.

I would like to know your thoughts on extension functions we saw. If you have any suggestion or correction to make this extension functions better feel free to drop a comment below or reach out to me on twitter.

That’s it for now folks :)

Thanks to Doris Liu and Nick Butcher for proofreading.

This was originally posted on Medium