On Android, there are three basic types of animation:

  1. The View animation: also called view animation or tween animation, mainly refers toandroid.view.animationSome classes below the package can only be set to View. The disadvantage is that, for example, when the control moves, the position of the control that receives the click does not follow the move, and the only effects that can be achieved are the move, zoom, rotate, and fade in and out operations and their combinations.
  2. Drawable animation: Also called Frame animation or Frame animation, it can be classified as view animation by showing a series of Drawable animations slide by slide.
  3. The Property animation: Property animation mainly refers toandroid.animationSome classes under the package, only forAPI 11Only the above version of Android system is valid, but we can make the lower version compatibility through the compatibility library. This animation can be set to any Object, including objects that have not yet been rendered to the screen. This animation is extensible, allowing you to customize any type and properties of the animation.

1, Drawable animation

Here, we’ll start with the Drawable animation because it’s relatively simple compared to the latter two. In the sample application we prepared a series of image resources and defined the animation resource record_im.xml under the drawable folder:


      
<animation-list android:oneshot="false"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/record0" android:duration="500"/>
    <item android:drawable="@drawable/record1" android:duration="500"/>
    <item android:drawable="@drawable/record2" android:duration="450"/>
    <item android:drawable="@drawable/record3" android:duration="400"/>
    <item android:drawable="@drawable/record4" android:duration="350"/>
    <item android:drawable="@drawable/record5" android:duration="400"/>
    <item android:drawable="@drawable/record6" android:duration="400"/>
</animation-list>
Copy the code

We then use the resource in our code and assign it to the ImageView. We then get the Drawable from the control and convert it to AnimationDrawable, and then we invoke its start() method to turn on the Drawable animation:

getBinding().ivRecord.setImageResource(R.drawable.record_anim);
animDraw = (AnimationDrawable) getBinding().ivRecord.getDrawable();
animDraw.start();
Copy the code

In addition, we can call the stop() method of the Drawable to stop the animation.

Frame animation considerations

When using frame animation, we should pay attention to the setting of pictures should not be too much, too large, in order to prevent the OOM due to insufficient memory.

2. View animation

2.1 Basic View animation

The resources of this animation are in the Android.view.animation package. There are mainly the following classes, which inherit from animation. We can use them to achieve complex animations. Each of these animation classes has a corresponding XML tag, so you can either define the animation in XML or implement the animation in code. The AnimationSet can be used to combine multiple animation effects. A comparison of predefined animations can be seen in the following diagram:

2.2 View animation properties

Of course, there are a lot of properties that need to be specified to implement an animation, and in XML we specify them using the properties of the tag, and in code we specify them using setter methods of the object. Thus, we can obtain the following correspondence:

The correspondence above is common to all View animations and has properties unique to each specific animation type. You can see what attributes are defined in each animation constructor by which fields they retrieve from the AttributeSet, but we won’t go into each of them here. Each predefined property Animation implements the Animation’s applyTransformation method in a different way. You can read the definition of this method to learn how to use these properties and how to achieve the effect of the View Animation.

For an AnimationSet, it maintains a list of animations and is itself an Animation, so a child AnimationSet can be added to an AnimationSet.

2.3 interpolator

As mentioned above, the View Animation is implemented using the applyTransformation method that overrides the Animation. Here we use AlphaAnimation as an example to see how it works, and you should pay attention to how the interpolator works. This method is looped through the Animation, which calculates a time based on the interpolator and passes it to the applyTransformation method.

Animation’s getTransformation method fragment:

if ((normalizedTime >= 0.0 f || mFillBefore) && (normalizedTime <= 1.0 f || mFillAfter)) {
    if(! mStarted) { fireAnimationStart(); mStarted =true;
        if (NoImagePreloadHolder.USE_CLOSEGUARD) {
            guard.open("cancel or detach or getTransformation"); }}if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0 f), 0.0 f);

    if (mCycleFlip) {
        normalizedTime = 1.0 f - normalizedTime;
    }

    final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
    applyTransformation(interpolatedTime, outTransformation);
}
Copy the code

The applyTransformation method of AlphaAnimation:

protected void applyTransformation(float interpolatedTime, Transformation t) {
    final float alpha = mFromAlpha;
    t.setAlpha(alpha + ((mToAlpha - alpha) * interpolatedTime));
}
Copy the code

Explicit, interpolatedTime here is a ratio. For example, if a transparent animation needs to last 10 seconds, the transparency needs to range from 0.5f to 1.0 F, and the interpolation rule is a quadratic function. So the transparency of the control at t (0

alpha = 0.5 f + (1.0 f - 0.5 f) * t^2 / 100
Copy the code

This is how the interpolator works, but you can also create your own interpolator to achieve the desired animation effect.

2.4 Use View animation

As an example, here we implement an animation that makes the control shake. Under the Anim folder, we define a panned animation and use the interpolator to make it repeat:

Anim /shake.xml:


      
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="700"
    android:fromXDelta="0.0"
    android:interpolator="@anim/cycle_7"
    android:toXDelta="15.0" />
Copy the code

The definition of the anim/ cicLE_7.xml interpolator:


      
<cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
    android:cycles="4.0" />
Copy the code

We then load the Animation in our code and call the control’s startAnimation() method to start the Animation:

getBinding().v.startAnimation(AnimationUtils.loadAnimation(this, R.anim.shake));
Copy the code

For the View, we have startAnimation() to start the animation on the View; ClearAnimation () is used to cancel the animation that the View is executing.

We can do the same with code without XML, which we won’t explain here.

2.5 Special use scenes of View animation

2.5.1 LayoutAnimation

A LayoutAnimation acts on a ViewGroup to animate all its children, usually to listViews. We can define the layout animation as follows:


      
<layoutAnimation 
    android:delay="500"
    android:animation="@anim/shake"
    xmlns:android="http://schemas.android.com/apk/res/android" />
Copy the code

Obviously, we need to reference another animation here. We can then specify the layoutAnimation in the ListView’s layoutAnimation property. Or apply the above animation by calling the setLayoutAnimation() method of the ListView.

2.5.2 switching Activity

We can use the Activity invokes the overridePendingTransition (state Richard armitage nim. Shake, state Richard armitage nim. Shake); Method to override the Activity’s switch animation. Note that this method should be called immediately after startActivity(Intent) or Finish ().

3. Property animation

3.1 Basic combing

We can learn about property animation by comparing View animation.

  1. Property animation is basicallyandroid.animationSome classes below the package.
  2. Property animation is based on the animation classAnimator; Property animations also provide us with several predefined classes:AnimatorSet.ObjectAnimator.TimeAnimatorValueAnimator; The inheritance relationship between these predefined classes is,AnimatorSetValueAnimatorDirectly inherited fromAnimatorAnd theObjectAnimatorTimeAnimatorInherited fromValueAnimator.
  3. Different from View animation, property animation is more widely used, it is not limited to View, essentially it is through modifying the control of the property value of the animation. There are limitations when you try to modify a property of an object, that is, the property animation requires that the object must provide a property of that propertysetterMethods.
  4. Property animations are also availablexmlAnd code two ways to define itxmlUsually defined asanimatorFolder, while the View animation is defined inanimUnder the folder.
  5. Property animation provides similar properties toAnimationUtilsTo load the property animation from the layout folder:AnimatorInflaterOf the classloadAnimator()Methods.
  6. Property animations also have their own interpolators:TimeInterpolator, and several predefined interpolators are also provided.
  7. We can also callViewMethod to use property animation, which we can do through Viewanimate()Method to obtain aViewPropertyAnimatorAnd then callViewPropertyAnimatorThe other methods make chain calls to achieve complex property animation effects.

Here is a comparison of the code implementation and XML implementation of property animation:

Above, we summarized some knowledge of property animation and compared it to View animation. This is a brief overview, and we’ll cover property animation in more detail in the following sections.

3.2 Using property animation

3.2.1 ValueAnimator

ValueAnimator is a base class for ObjectAnimator and TimeAnimator. We can use it like this:

ValueAnimator anim = ValueAnimator.ofFloat(0f.1f);
anim.setDuration(300);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float currentValue = (float) animation.getAnimatedValue();
        Log.d("TAG"."cuurent value is "+ currentValue); }}); anim.start();Copy the code

Here we use log to print out the process of value gradient. From the log, you can see that the effect is to increase the value from 0 to 1. Animation can also be achieved if we modify the properties of the control based on the values in this listener method. In addition to ofFloat(), there are methods such as ofInt(), which have similar effects.

3.2.2 ObjectAnimator

Above, if we want to achieve animation effects, need to modify attributes of the object in the ValueAnimator listening to events, the ObjectAnimator here, we only need the incoming object instances and attributes of string name, modify the attributes of the object operation can be done automatically. For example, the effect of the following program is that the transparency of the textView control will change from 1 to 0 and back to 1 in 5 seconds.

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha".1f.0f.1f);
animator.setDuration(5000);
animator.start();
Copy the code

Note that we pass alpha, which does not itself exist in the control, but instead has a method called setAlpha(). That is, ObjectAnimator works by reflecting setter methods instead of modifying properties. You can learn more about this in the PropertyValuesHolder class.

PropertyValuesHolder wraps information about the object and method of the property we want to modify, and then uses reflection to trigger the method of the specified object to complete the modification of the object property. Among them

void setupSetter(Class targetClass) { Class<? > propertyType = mConverter ==null ? mValueType : mConverter.getTargetType();
    mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", propertyType);
}
Copy the code

It’s going to look for the setter method that we’re going to modify the property, and then

void setAnimatedValue(Object target) {
    if(mProperty ! =null) {
        mProperty.set(target, getAnimatedValue());
    }
    if(mSetter ! =null) {
        try {
            mTmpValueArray[0] = getAnimatedValue();
            mSetter.invoke(target, mTmpValueArray);
        } catch (InvocationTargetException e) {
            Log.e("PropertyValuesHolder", e.toString());
        } catch (IllegalAccessException e) {
            Log.e("PropertyValuesHolder", e.toString()); }}}Copy the code

Setter methods are fired to modify the properties of the object.

3.2.3 AnimatorSet

AnimatorSet provides a Builder within AnimatorSet to help us build composite animations. AnimatorSet.Builder provides the following four methods:

  1. after(Animator anim): Inserts the existing animation after the incoming animation
  2. after(long delay): Delays execution of an existing animation by a specified millisecond
  3. before(Animator anim): Inserts the existing animation before the incoming animation
  4. with(Animator anim): Executes an existing animation and an incoming animation simultaneously

When we call the Play () method of the AnimatorSet, we get an instance of AnimatorSet.Builder, and then we can make chain calls using the constructor’s method:

ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f.0f);
ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation".0f.360f);
ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha".1f.0f.1f);
AnimatorSet animSet = new AnimatorSet();
animSet.play(rotate).with(fadeInOut).after(moveIn);
animSet.setDuration(5000);
animSet.start();
Copy the code

3.2.4 TypeEvaluator

As mentioned earlier, property animations also have their own interpolators, which we can use to specify the rate at which properties change over a period of time. The interpolating function yields a scale, which is meaningless. In the AlphaAnimation of the View animation, if we specify the start and end transparency, we can use the transparency calculation rules to get the transparency at a certain time. But for property animation, because it can be applied to any property, and this property can be of any type, what calculation rules will apply to this property? This requires us to specify a calculation rule using TypeEvaluator. That is, TypeEvaluator is a rule for evaluating properties of property animations.

The following is the definition of TypeEvaluator. The three parameters here are: fraction is the current ratio, which can be calculated by an interpolator; StartValue and endValue are the starting and ending values for attribute changes, respectively. The result it returns is the value of an attribute at that point in time.

public interface TypeEvaluator<T> {
    public T evaluate(float fraction, T startValue, T endValue);
}
Copy the code

Property animations have provided us with several predefined TypeEvaluators, such as FloatEvaluator:

public class FloatEvaluator implements TypeEvaluator<Number> {
    public Float evaluate(float fraction, Number startValue, Number endValue) {
        float startFloat = startValue.floatValue();
        returnstartFloat + fraction * (endValue.floatValue() - startFloat); }}Copy the code

A predefined TypeEvaluator is selected in the PropertyValuesHolder of the property animation based on the type of the property. However, if the type of our property is not within the predefined range, we need to implement a TypeEvaluator ourselves. Let’s implement a TypeEvaluator using a date type as an example.

When we get a ValueAnimator instance using ValueAnimator’s ofObject() method, we are required to pass in a TypeEvaluator, so we can define it as follows:

private static class DateEvaluator implements TypeEvaluator<Date> {

    @Override
    public Date evaluate(float fraction, Date startValue, Date endValue) {
        long startTime = startValue.getTime();
        return new Date((long) (startTime + fraction * (endValue.getTime() - startTime))); }}Copy the code

Then, we can use it like this:

ValueAnimator animator = ValueAnimator.ofObject(new DateEvaluator(), new Date(0), new Date());
animator.setDuration(5000);
animator.addUpdateListener(animation -> {
    Date date = (Date) animation.getAnimatedValue();
    LogUtils.d(date);
});
animator.start();
Copy the code

This will get all the date changes from 0 to the current time in 5 seconds.

3.2.5 TimeInterpolator

Just like the View animation, we can specify an interpolator for the property animation. The interpolator is used to set the rate at which a value changes over a specified period of time. In attribute animation, the interpolator is TimeInterpolator, which also has several default implementations:

  1. AccelerateDecelerateInterolator: Accelerate first and then decelerate.
  2. AccelerateInterpolator: to speed up.
  3. DecelerateInterpolator: slow down.
  4. AnticipateInterpolator: First change a segment in the opposite direction and then speed up the playback.
  5. AnticipateOvershootInterpolator: First change in the opposite direction, then accelerate the playback, will exceed the target value and slowly move to the target value, similar to spring rebound.
  6. BounceInterpolator: Jumps as it nears the target value.
  7. CycleIinterpolatorMath.sin(2 * mCycles * math.pi * input).
  8. LinearInterpolator: Linear uniform change.
  9. OvershottInterpolator: Finally exceeds the target value and slowly changes to the target value.

3.2.6 Animating properties in XML

We can define a property animation like this,

<set android:ordering=["together"|"sequentially"] >
    <objectAnimator
        android:propertyName="string"
        android:duration="int"
        android:valueFrom="float | int | color"
        android:valueTo="float | int | color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["repeat"|"reverse"]
        android:valueType=["intType"|"floatType"]/>
    <animator
        android:duration="int"
        android:valueFrom="float | int | color"
        android:valueTo="float | int | color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["repeat"|"reverse"]
        android:valueType=["intType"|"floatType"]/>
    <set>.</set>
</set>
Copy the code

The android:ordering method is used to control the ordering of subsequences or the simultaneous ordering of subsequences. Two optional parameters are as follows: Sequentially. Together (default) indicates that the animation starts at the same time.

The

tag here means the following:

After defining the property animation in the XML, we can get the animation instance in our code via the utility class and use:

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.animtor.property_animator);
set.setTarget(myObject);
set.start();
Copy the code

4. Precautions for using animation

  1. Running out of memory: Avoid OOM for too many images when using frame animation.
  2. The View animation doesn’t really change the position of the View:ViewAnimation hasn’t really changedViewAttribute of, namelyViewThe animation does not change after executionViewThe real layout property value of. Let’s say we have one in the layoutButtonAt the top of the screen, we’ve set the pan animation to move to the bottom of the screen and keep the last execution of the animation at the bottom of the screen, so if I click on the bottom of the screen after the execution of the animationButtonThere is no response, and clicking on the top of the original screen is notButtonIs responding to a clickButtonIn the event.
  3. Memory leak: When animating properties, when animating an infinite loop, you need to stop the animation when the Activity exits. Otherwise, you may leak the Activity’s memory because it cannot release resources.
  4. Animation compatibility: When the APP needs to be compatible with API 11, it needs to pay attention to the compatibility of animation.
  5. Use DP instead of PXBecause:pxCompatibility issues on different devices, try to use when using animationdpAs a unit.
  6. Hardware acceleration: Use hardware acceleration to improve animation fluency.