preface

UI changes are common in Android development, and if you don’t overdo it with animation, the user experience isn’t great. I will divide the animation into three categories: View animation, frame animation and property animation. Let’s start with View animation

First, View animation

View animations include the following types

  • ScaleAnimation
  • TranslateAnimation
  • AlphaAnimation
  • RotateAnimation

We also provide an AnimationSet class to display multiple View animations together. We can create these Animation objects directly in code or specify them in XML

Zoom animation

  • Defined in code
ScaleAnimation sAnimation = new ScaleAnimation(0.1.0.1, Animation.RELATIVE_TO_SELF, 0.5 f, 
                Animation.RELATIVE_TO_SELF, 0.5 f);
animation.setDuration(2000);
imageView.startAnimation(sAnimation);
Copy the code
  • Defined in the XML
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXScale="0" android:toXScale="1" android:fromYScale="0"
    android:toYScale="1" android:pivotX="50%" android:pivotY="50%" android:duration="2000">
</scale>
Copy the code

Translation of animation

  • Defined in code
TranslateAnimation tAnimation = new TranslateAnimation(0.100.0.100);
tAnimation.setDuration(2000);
imageView.startAnimation(tAnimation);
Copy the code
  • Defined in the XML
<translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000" android:fromXDelta="0" 
    android:toXDelta="200" android:fromYDelta="0" android:toYDelta="200">
</translate>
imageView.startAnimation(AnimationUtils.loadAnimation(this, R.anim.translate));
Copy the code

Transparency animation

  • Defined in code
AlphaAnimation aAnimation = new AlphaAnimation(0, 1);
aAnimation.setDuration(2000);
imageView.startAnimation(aAnimation);
Copy the code
  • Defined in the XML
<alpha xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000"
    android:fromAlpha="0" android:toAlpha="1">
</alpha>
Copy the code

Rotating animation

  • Defined in code
RotateAnimation rAnimation = new RotateAnimation(0, 360, animation. RELATIVE_TO_SELF, 0.5f, animation. RELATIVE_TO_SELF, 0.5 f); rAnimation.setDuration(2000); imageView.startAnimation(rAnimation);Copy the code
  • Defined in the XML
<rotate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000" 
    android:fromDegrees="0" android:toDegrees="360">
</rotate>
Copy the code

Combination of animation

  • Defined in code
AnimationSet set = new AnimationSet(true);
set.addAnimation(sAnimation);
set.addAnimation(aAnimation);
set.addAnimation(tAnimation);
set.addAnimation(rAnimation);
// All child animations will be set to this timeout
set.setDuration(5000);
imageView.startAnimation(set);
Copy the code
  • Defined in the XML
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha 
        android:duration="2000"
        android:fromAlpha="0" 
        android:toAlpha="1">
    </alpha>
    <rotate 
        android:duration="2000"
        android:fromDegrees="0" 
        android:toDegrees="360">
    </rotate>
    <scale
        android:fromXScale="0" 
        android:toXScale="1" 
        android:fromYScale="0"
        android:toYScale="1"
        android:pivotX="50%" 
        android:pivotY="50%"
        android:duration="2000">
    </scale>
    <translate 
        android:duration="2000" 
        android:fromXDelta="0"
        android:toXDelta="200" 
        android:fromYDelta="0" 
        android:toYDelta="200">
    </translate>
</set>
Copy the code

There are a few things to note about this code

  • Animations defined in XML can passAnimationUtils.loadAnimation(context, resId))Get the corresponding Animation object
  • You can set it if you want to delay an animationstartOffset
  • You can set it if you want an animation loop to runrepeatCount
  • The animation will be returned to the original position by default if you don’t need to return to the original positionsetFillAfterSet to true, but it will remain in the position after execution but will not respond to click events, the original position will respond to click events
  • None of the above animations has an interpolator set. The default interpolator is usedAccelerateDecelerateInterpolatorIf you want the animation to run at a constant rate, you can set the following interpolators
Interpolator class Id of the XML resource Change way
AccelerateDecelerateInterpolator @android:anim/accelerate_decelerate_interpolator Speed up and then slow down
AccelerateInterpolator @android:anim/accelerate_interpolator Has been accelerated
AnticipateInterpolator @android:anim/anticipate_interpolator Go some distance in the opposite direction before you go forward
AnticipateOvershootInterpolator @android:anim/anticipate_overshoot_interpolator First move in the opposite direction, then advance and pass the target point, and finally return to the target point
BounceInterpolator @android:anim/bounce_interpolator Similar to how the ball bounces when it hits the ground
CycleInterpolator @android:anim/cycle_interpolatorr Cycle, you go in the forward direction to the end, and then you go in the opposite direction until you get to -end and then you come back
DecelerateInterpolator @android:anim/decelerate_interpolator Has been slow
LinearInterpolator @android:anim/linear_interpolator Uniform motion
OvershootInterpolator @android:anim/overshoot_interpolator Move past the target point and then come back

LayoutAnimation

If a ViewGroup is set to this property then the animation will be executed when the ViewGroup is first displayed as follows.

First define an AnimationSet

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:duration="2000"
        android:fromAlpha="0"
        android:toAlpha="1">
    </alpha>
    <translate
        android:duration="2000"
        android:fromYDelta="100%p"
        android:toYDelta="0">
    </translate>
</set>
Copy the code

{layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation: layoutAnimation The first item will be animated at 600ms and the second at 1200ms

<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animationOrder="normal"
    android:animation="@anim/set"
    android:delay="0.3">
</layoutAnimation>
Copy the code

Finally, set the LayoutAnimation to the destination ViewGroup

<android.support.v7.widget.RecyclerView
    android:id="@+id/rv"
    android:background="@color/colorPrimary"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layoutAnimation="@anim/layout_animation"
    android:orientation="vertical">

</android.support.v7.widget.RecyclerView>
Copy the code

The running effect is shown in the picture below. Of course, it is a little ugly. You can adjust it slowly if necessary

Second, frame animation

Frame animation is a set of images played in a particular order, as shown below

<animation-list xmlns:android="http://schemas.android.com/apk/res/android" 
    android:oneshot="true">
    <item android:drawable="@drawable/s1" android:duration="1000"/>
    <item android:drawable="@drawable/s2" android:duration="1000"/>
    <item android:drawable="@drawable/s3" android:duration="1000"/>
    <item android:drawable="@drawable/s4" android:duration="1000"/>
    <item android:drawable="@drawable/s5" android:duration="1000"/>
    <item android:drawable="@drawable/s6" android:duration="5000"/>
    <item android:drawable="@drawable/s7" android:duration="1000"/>
</animation-list>imageView.setImageResource(R.drawable.list); mDrawable = (AnimationDrawable)imageView.getDrawable(); imageView.post(new Runnable() { @Override public void run() { mDrawable.start(); }});Copy the code

There are a couple of caveats here

  • oneshotIndicates whether to play only once. The default value is false for loop play
  • Frame animation will only show the first frame until the View process is completed, so it should be started after the View process is completed

Property animation

ObjectAnimator is derived from ValueAnimator. The ObjectAnimator class is derived from ValueAnimator. The ObjectAnimator class is derived from ValueAnimator. Let’s start with the ViewPropertyAnimator

  • ViewPropertyAnimator
  • ValueAnimator
  • ObjectAnimator
  • AnimatorSet

ViewPropertyAnimator

The interior of this class is actually implemented through ValueAnimator. We can get the objects of this class through view.animator()

// Translation slowly changes from the current value to 100
imageView.animate().translationX(100);
// Translation slowly changes from current value to original value +100
imageView.animate().translationXBy(100);
// Reverse 180 degrees
imageView.animate().rotation(180);
Copy the code

Note that we don’t need to call the start method manually to start it automatically, with a default duration of 300ms

ValueAnimator

ValueAnimator instances can be obtained via ofInt, ofFloat, ofArgb, etc. Here is an example of dynamically changing the height of an image via property animation

Defined in code

ValueAnimator vAnimator = ValueAnimator.ofInt(400.0);
vAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        ViewGroup.LayoutParams params = imageView.getLayoutParams();
        params.height = (int) animation.getAnimatedValue(); imageView.setLayoutParams(params); }}); vAnimator.setDuration(3000);
vAnimator.start();
Copy the code

Defined in XML

<animator xmlns:android="http://schemas.android.com/apk/res/android" android:valueFrom="400dp" 
android:valueType="intType" android:valueTo="0dp" android:duration="3000">
</animator>
ValueAnimator vAnimator =
                (ValueAnimator) AnimatorInflater.loadAnimator(this, R.animator.animator);
Copy the code

ObjectAnimator

ObjectAnimator instances can be obtained via ofInt, ofFloat, ofArgb, etc., and generally operate on the following properties

  • TranslationX, translationY translation
  • Rotation, rotationX, rotationY
  • PrivotX and privotY control the fulcrum position of rotation and scaling
  • Alpha transparency
  • X, y, z position

The following is an example of dynamically changing the transparency of an image by animating properties

Defined in code

ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "alpha".0.1);
animator.setDuration(3000);
animator.start();
Copy the code

Defined in XML

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:valueType="floatType" android:duration="3000" android:propertyName="alpha"
    android:valueFrom="0" android:valueTo="1">
</objectAnimator>
ObjectAnimator animator = (ObjectAnimator)
                AnimatorInflater.loadAnimator(this, R.animator.object_animator);
animator.setTarget(imageView);
animator.start();
Copy the code

A few notes:

  • If the ofXXX attribute name parameter is followed by only one parameter that represents the target value, the system will callgetterGet the initialization value and keep callingsetterSetting, when you exceed one parameter the first one becomes the initial value and the last one becomes the target value, and the ones in between are transition points and you don’t have to provide thatsettermethods
  • When we need to animate a property of a class that doesn’t provide setter methods, we can build a wrapper class
  • If you find that the properties of your custom View are not changed by animating the properties, check that your setter methods do not trigger a redraw

AnimatorSet

An AnimatorSet is similar to an AnimationSet. It is used to animate multiple properties together

Defined in code

ValueAnimator vAnimator =
                (ValueAnimator) AnimatorInflater.loadAnimator(this, R.animator.animator);
vAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        ViewGroup.LayoutParams params = imageView.getLayoutParams();
        params.height = (int) animation.getAnimatedValue(); imageView.setLayoutParams(params); }}); vAnimator.setDuration(3000);
vAnimator.start();
ObjectAnimator oAnimator = (ObjectAnimator)
        AnimatorInflater.loadAnimator(this, R.animator.object_animator);
oAnimator.setTarget(imageView);
oAnimator.start();
AnimatorSet set = new AnimatorSet();
// Execute simultaneously
set.playTogether(vAnimator, oAnimator);
// Execute sequentially
set.playSequentially(vAnimator, oAnimator);
Copy the code

Define in XML where ordering means simultaneous or sequential execution

<set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="together">
    <animator android:valueFrom="400px"
        android:valueTo="0px" android:duration="3000" android:valueType="intType">
    </animator>
    <objectAnimator
        android:valueType="floatType" android:duration="3000" android:propertyName="alpha"
        android:valueFrom="0" android:valueTo="1">
    </objectAnimator>
</set>
Copy the code

PropertyValuesHolder

Multiple animations can also be executed simultaneously using PropertyValuesHolder

PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("alpha", 0, 1);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofInt("rotation", 0, 360);
ValueAnimator animator = ObjectAnimator.ofPropertyValuesHolder(holder1, holder2);
animator.setDuration(3000);
animator.setTarget(imageView);
animator.start();
Copy the code

Set ViewGroup’s animateLayoutChanges property to true. Animations will occur when views are added or removed