animations

There is new animation engine since Android 3.0 called property animation.

Animator is a base class to perform animation from start value to end value using given interpolator and value evaluator. There are following animators:

  • ValueAnimator - the main timing engine for property animation that also computes the values for the property to be animated.
  • ObjectAnimator - a subclass of ValueAnimator that updates the specified property accordingly when it computes a new value for the animation.
  • AnimatorSet provides a mechanism to group animations together so that they run in relation to one another.

The StateListAnimator lets you define animators that run when the state of a view changes. This object behaves as a wrapper for an Animator object (it is not subclass of Animator), calling that animation whenever the specified view state such as "pressed" changes.

AnimatorInflater allows to inflate animator resource.

val animator = AnimatorInflater.loadAnimator(context, R.animator.myanimator) 
       as ObjectAnimator

TypeEvaluator interface allows to supply custom evaluators for types that are not automatically understood and used by the animation system. There are built-in evaluators such as FloatEvaluator.

TimeInterpolator interface allows to define the rate of change of an animation. This allows animations to have non-linear motion, such as acceleration and deceleration. For example, AccelerateDecelerateInterpolator is the default interpolator.

LayoutTransition enables automatic animations on layout changes in ViewGroup objects. It's easy to use, but not as powerful as the transition API.

events

Animator.AnimatorListener allows you to handle animation lifecycle events, it has following methods:

  • onAnimationStart() - called when the animation starts.
  • onAnimationEnd() - called when the animation ends.
  • onAnimationRepeat() - called when the animation repeats itself.
  • onAnimationCancel() - called when the animation is canceled. A cancelled animation also calls onAnimationEnd(), regardless of how they were ended.

AnimatorListenerAdapter is an empty implementation of AnimatorListener.

ValueAnimator.AnimatorUpdateListener allows you to handle every frame of animation, i.e. events when new the calculated value generated. Implementing this listener is required if you use ValueAnimator.

AnimatorUpdateListener example
ValueAnimator.ofObject(...).apply {
    ...
    addUpdateListener { updatedAnimation ->
        // You can use the animated value in a property that uses the
        // same type as the animation. In this case, you can use the
        // float value in the translationX property.
        textView.translationX = updatedAnimation.animatedValue as Float
    }
    ...
}

Depending on what property or object you are animating, you might need to call invalidate() on a View to force that area of the screen to redraw itself with the new animated values.

For example, animating the color property of a Drawable object only cause updates to the screen when that object redraws itself. All of the property setters on View, such as setAlpha() and setTranslationX() invalidate the View properly, so you do not need to invalidate the View when calling these methods with new values.

value animator

The ValueAnimator class lets you animate values of some type for the duration of an animation. There are factory methods for different types:

  • ofInt() - animates between int values
  • ofFloat() - animates between float values
  • ofObject() - animates between Object values, you need provide TypeEvaluator.
  • ofArgb() - animates between color values
Declare ValueAnimator xml resource
<!-- file res/animator/myanimator.xml -->
<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:valueFrom="1"
    android:valueTo="0"
    android:valueType="floatType"
    android:repeatCount="1"
    android:repeatMode="reverse"/<
Animate text size with ValueAnimator
// in real world ObjectAnimator will be used
val vanimator = ValueAnimator.ofFloat(10f, 80f).apply {
    duration = 2000
    interpolator = CycleInterpolator(5f)
    repeatMode = ValueAnimator.REVERSE
    startDelay = 200
            
    addUpdateListener { animation ->
        txtView.textSize = animation.animatedValue as Float
        }
    }
        
vanimator.start()

object animator

The invalidate() method is automatically called to refresh the screen whenever a following view's properties are changed:

  • translationX and translationY control where the View is located as a delta from its left and top coordinates which are set by its layout container.
  • rotation, rotationX, and rotationY control the rotation in 2D (rotation property) and 3D around the pivot point.
  • scaleX and scaleY control the 2D scaling of a View around its pivot point.
  • pivotX and pivotY control the location of the pivot point, around which the rotation and scaling transforms occur. By default, the pivot point is located at the center of the object.
  • x and y are simple utility properties to describe the final location of the View in its container, as a sum of the left and top values and translationX and translationY values.
  • alpha represents the alpha transparency on the View. This value is 1 (opaque) by default, 0 means full transparency (not visible).
Declare ObjectAnimator xml resource
<!-- file res/animator/myanimator.xml -->
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
                android:duration="250"
                android:propertyName="alpha"
                android:valueFrom="0.8"
                android:valueTo="0.4"
                android:valueType="floatType"/>
Animate alpha property with ObjectAnimator
// load animator from resource
val animator = AnimatorInflater.loadAnimator(context, R.animator.myanimator) as ObjectAnimator
    animator.target = imgView
    // ... setup other stuff if necessary
animator.start()

// create animator programmatically
val animator: ObjectAnimator = ObjectAnimator.ofFloat(imgView, "alpha", 0.8f, 0.4f)
    animator.duration = 250
    // ... setup other stuff if necessary
animator.start()

animator set

AnimatorSet allows to play a set of Animator objects in the specified order. Animations can be set up to play together, in sequence, or after a specified delay.

Nested AnimatorSet are allowed.

Declare animator set xml resource
<set android:ordering="sequentially">
    <set>
        <objectAnimator
            android:propertyName="x"
            android:duration="500"
            android:valueTo="400"
            android:valueType="intType"/>
        <objectAnimator
            android:propertyName="y"
            android:duration="500"
            android:valueTo="300"
            android:valueType="intType"/>
    </set>
    <objectAnimator
        android:propertyName="alpha"
        android:duration="500"
        android:valueTo="1f"/>
</set>
Create animator set programmatically
/*
Plays bounceAnim.
Plays squashAnim1, squashAnim2, stretchAnim1, and stretchAnim2 at the same time.
Plays bounceBackAnim.
Plays fadeAnim.
*/
val bouncer = AnimatorSet().apply {
    play(bounceAnim).before(squashAnim1)
    play(squashAnim1).with(squashAnim2)
    play(squashAnim1).with(stretchAnim1)
    play(squashAnim1).with(stretchAnim2)
    play(bounceBackAnim).after(stretchAnim2)
}
val fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply {
    duration = 250
}
AnimatorSet().apply {
    play(bouncer).before(fadeAnim)
    start()
}

state list animator

Use StateListAnimator to animate the view's state changing.

  1. define state list animator as resource
  2. attach the state list animator to a view assigning value to the android:stateListAnimator attribute
Using StateListAnimator
<!-- file res/xml/animate_scale.xml  -->
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- the pressed state; increase x and y size to 150% -->
    <item android:state_pressed="true">
        <set>
            <objectAnimator android:propertyName="scaleX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1.5"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="scaleY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1.5"
                android:valueType="floatType"/>
        </set>
    </item>
    <!-- the default, non-pressed state; set x and y size to 100% -->
    <item android:state_pressed="false">
        <set>
            <objectAnimator android:propertyName="scaleX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="scaleY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1"
                android:valueType="floatType"/>
        </set>
    </item>
</selector>
<!-- in some layout file --> <Button android:stateListAnimator="@xml/animate_scale" ... />

You can also play a drawable animation between state changes, using AnimatedStateListDrawable. Some of the system widgets in Android 5.0 use these animations by default.

Declare AnimatedStateListDrawable xml resource

layout transitions

LayoutTransition allows to animate an appearing and disappearing view in ViewGroup. The remaining views in the ViewGroup can also animate into their new positions when you add or remove Views.

  1. enable transitions in xml layout for your container
  2. optionally set transition type by setting flags:
    • APPEARING - animation runs on those items that are appearing in the container.
    • CHANGE_APPEARING - animation runs on those items that are changing due to a new item appearing in the container.
    • CHANGE_DISAPPEARING - animation runs on those items that are changing due to a new item appearing in the container.
    • CHANGING - animation runs on those items that are changing due to a layout change not caused by items being added to or removed from the container.
    • DISAPPEARING - animation runs on those items that are disappearing from the container.

The default CHANGE_APPEARING animation animates the left, top, right, bottom, scrollX, and scrollY properties. Values for these properties are updated with the pre- and post-layout values when the transition begins.

LayoutTransition usage
<!-- enable layout animations -->
<LinearLayout
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:id="@+id/verticalContainer"
    android:animateLayoutChanges="true" />

viewGroup.layoutTransition .enableTransitionType(LayoutTransition.CHANGING)

time interpolators

There are built-in interpolators. Also you can create own interpolator by implementing the TimeInterpolator interface.

// AccelerateDecelerateInterpolator implementation
override fun getInterpolation(input: Float): Float =
        (Math.cos((input + 1) * Math.PI) / 2.0f).toFloat() + 0.5f
class description
AccelerateDecelerateInterpolator An interpolator whose rate of change starts and ends slowly but accelerates through the middle.
AccelerateInterpolator An interpolator whose rate of change starts out slowly and then accelerates.
AnticipateInterpolator An interpolator whose change starts backward then flings forward.
AnticipateOvershootInterpolator An interpolator whose change starts backward, flings forward and overshoots the target value, then finally goes back to the final value.
BounceInterpolator An interpolator whose change bounces at the end.
CycleInterpolator An interpolator whose animation repeats for a specified number of cycles.
DecelerateInterpolator An interpolator whose rate of change starts out quickly and then decelerates.
LinearInterpolator An interpolator whose rate of change is constant.
OvershootInterpolator An interpolator whose change flings forward and overshoots the last value then comes back.