ImageView

The following is the primary function we can use to create our animation:

fun Context.animateSmoothly(

@ColorRes startColorId: Int,

@ColorRes endColorId: Int,

doUpdate: (Int) -> Unit

): ValueAnimator =

createAnimator(

ArgbEvaluator(),

colors[startColorId],

colors[endColorId],

onConfig = {

duration = 1000

repeatMode = ValueAnimator.REVERSE

repeatCount = ValueAnimator.INFINITE

start()

},

onUpdate = doUpdate

)

To use it we can call it directly in our Activity like:

val imageViewBackground = ColorDrawable()

imageView.background = imageViewBackground animateSmoothly(

R.color.loading_animation_start,

R.color.loading_animation_end

) {

imageViewBackground.color = it

}

Resources

A previous article (Extending Resources) explains the technique used to retrieve the resources in animateSmoothly() .

createAnimator( … )

This function extends the system’s ValueAnimator.ofObject() with some utils to make it easier to use.



evaluator: TypeEvaluator<*>,

vararg values: T,

onConfig: ValueAnimator.() -> Unit = {},

onUpdate: (T) -> Unit

): ValueAnimator =

ValueAnimator.ofObject(evaluator, *values).apply {

addUpdateListener {



onUpdate(it.animatedValue as T)

}

onConfig(this)

} fun createAnimator(evaluator: TypeEvaluator,vararg values: T,onConfig: ValueAnimator.() -> Unit = {},onUpdate: (T) -> Unit): ValueAnimator =ValueAnimator.ofObject(evaluator, *values).apply {addUpdateListener { @Suppress ("UNCHECKED_CAST")onUpdate(it.animatedValue as T)onConfig(this)

The first two parameters are used to create the actual ValueAnimator . We use the third and fourth parameters after creating the animator. The optional onConfig lambda is called to mutate properties of the ValueAnimator . onUpdate is used to forward updates with an adapter of addUpdateListener . It also adds extra type safety.

onConfig = { … }

onConfig = {

duration = 1000

repeatMode = ValueAnimator.REVERSE

repeatCount = ValueAnimator.INFINITE

start()

}

The onConfig shown in our example does 4 things:

Sets the duration to 1 second (1000ms):

duration = 1000

Tells the animator to repeat by reversing the animation:

repeatMode = ValueAnimator.REVERSE

Let’s the animator know that the animation has no end:

repeatCount = ValueAnimator.INFINITE

Starts the animation

start()

How it looks

The image view shows like this when loading:

Once finished loading, the animation will continue, so it’s advised to stop it once we have content. But we’ll see how to do this later on.