Reprinted from: http://blog.csdn.net/lmj623565791/article/details/38067475
1. Overview
Android offers several types of animation: View Animation, Drawable Animation, Property Animation. View Animation is quite simple, but it can only support simple zooming, translation, rotation, transparency basic animation, and has certain limitations. For example: you want View to have a color switching animation; you want to use 3D rotating animation; you want the position of View to be the current position when the animation stops; none of these View Animations can do it. This is why Property Animation came into being. This blog details the use of Property Animation. As for Drawable Animation, well, slightly~
2. Related API
The original name of Property Animation is to change the attributes of objects by animation. First, we need to understand several attributes:
Duration animation duration, default 300ms.
Time interpolation: At first glance, I don't know what the time difference is, but I say Linear Interpolator, Accelerate Decelerate Interpolator, you must know what it is and define the rate of change in animation.
Repeat count and behavior: Repeat number, and repeat pattern; you can define how many repeats; repeat from scratch or reverse.
Animator sets: A collection of animations. You can define a set of animations to be executed together or sequentially.
Frame refresh delay: Frame refresh delay, how often to refresh a frame for your animation; default is 10 ms, but ultimately depends on the current state of the system; basically no matter.
Related classes
ObjectAnimator Animation Execution Class, described in detail later
The execution class of ValueAnimator animation, described in detail later
AnimatorSet is used to control the execution of a set of animations: linear, together, the execution of each animation, etc.
Animator Inflater User Loads xml Files for Attribute Animation
Type Evaluator type valuation is mainly used to set the value of animation operation properties.
TimeInterpolator time interpolation, as described above.
Generally speaking, attribute animation is that the animation execution class sets the attributes, duration, start and end attributes, time difference, etc. of the animation operation object, and then the system will dynamically change the attributes of the object according to the set parameters.
3. Object Animator Realizes Animation
Object Animator was chosen as the first because it is the simplest line of code to implement animation in seconds. Here's an example:
Layout file:
[html] view plain copy
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/id_container" > <ImageView android:id="@+id/id_ball" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:src="@drawable/mv" android:scaleType="centerCrop" android:onClick="rotateyAnimRun" /> </RelativeLayout>
It's simple, just a picture of a sister.~
Activity code:
[java] view plain copy
package com.example.zhy_property_animation; import android.animation.ObjectAnimator; import android.app.Activity; import android.os.Bundle; import android.view.View; public class ObjectAnimActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.xml_for_anim); } public void rotateyAnimRun(View view) { ObjectAnimator// .ofFloat(view, "rotationX", 0.0F, 360.0F)// .setDuration(500)// .start(); } }
Effect:
Is it possible to achieve simple animation in one line of code?
For ObjectAnimator
1. Offering ofInt, ofFloat, ofObject, these methods are to set the elements of animation, the attributes of animation, the start, end of animation, and any attribute values in the middle.
When only one attribute value is set, it is assumed that the value of the attribute of the object is the beginning (getPropName reflection acquisition), and then the value is the end point. If two are set, one is the beginning and the other is the end.~~~
In the process of animation updating, setPropName is constantly called to update the attributes of the element. All updates to an attribute using ObjectAnimator must have getter (when setting an attribute value) and setter method.~
2. If you operate on the property method of the object, such as setRotation X in the example above, if you do not call view redrawing internally, you need to call it manually in the following way.
[java] view plain copy
anim.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // view.postInvalidate(); // view.invalidate(); } });
3. Looking at the example above, because there is only one attribute set for the operation, what if I want an animation to make the View both narrow and fade out (three attributes scaleX,scaleY,alpha), using only Object Animator?
The idea is not very good, you might say using AnimatorSet, which looks like a bunch of cartoon plugs to execute together, but I prefer to use an Object Animator instance to implement it. ~Look at the code below:?
[java] view plain copy
public void rotateyAnimRun(final View view) { ObjectAnimator anim = ObjectAnimator// .ofFloat(view, "zhy", 1.0F, 0.0F)// .setDuration(500);// anim.start(); anim.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float cVal = (Float) animation.getAnimatedValue(); view.setAlpha(cVal); view.setScaleX(cVal); view.setScaleY(cVal); } }); }
Write a string of attributes that the object does not have, that is, whatever ~~we just need the value it calculates in terms of time interpolation and duration, we call it manually by ourselves.~
Effect:
This example is to illustrate that sometimes a different way of thinking is not constrained by the API, using some of the functions provided by the API can also achieve interesting results.~~~
For example: you want to achieve parabolic effect, horizontal direction 100px/s, vertical direction acceleration 200px/s*s, how to achieve it ~~You can try it with Object Animator.~
4. There's actually a simpler way to change multiple effects in an animation: using propertyValuesHolder
[java] view plain copy
public void propertyValuesHolder(View view) { PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f); PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f); PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f); ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY,pvhZ).setDuration(1000).start(); }
4. Realization of Animation by Value Animator
Similar to the Object Animator usage, take a brief look at the animation code that moves vertically with view:
[java] view plain copy
public void verticalRun(View view) { ValueAnimator animator = ValueAnimator.ofFloat(0, mScreenHeight - mBlueBall.getHeight()); animator.setTarget(mBlueBall); animator.setDuration(1000).start(); }
Does it make you feel like, Daddy, it's different from Value Animator's wool yarn ~But if you look closely, you can see that there's no attribute set for the operation ~That is to say, the above code has no effect, no attribute specified ~?
That's the difference from Value Animator: Value Animator doesn't operate on attributes, and you might ask what's the benefit of that? Didn't I have to set it manually?
Benefits: The properties of objects that do not need to be manipulated must have getter and setter methods. You can manipulate any attributes by yourself based on the current animation calculation value. Remember the one above. [I hope an animation can make View both narrow and fade out (three attributes scaleX,scaleY,alpha)] That's the way it's actually used.~
Example:
Layout file:
[html] view plain copy
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/id_container" > <ImageView android:id="@+id/id_ball" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/bol_blue" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="horizontal" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="verticalRun" android:text="vertical" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="paowuxian" android:text="parabola" /> </LinearLayout> </RelativeLayout>
A small ball in the upper left corner and two buttons at the bottom. ~Let's first look at the code of a free fall body.
[java] view plain copy
/** * Free falling body * @param view */ public void verticalRun( View view) { ValueAnimator animator = ValueAnimator.ofFloat(0, mScreenHeight - mBlueBall.getHeight()); animator.setTarget(mBlueBall); animator.setDuration(1000).start(); // animator.setInterpolator(value) animator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mBlueBall.setTranslationY((Float) animation.getAnimatedValue()); } }); }
Unlike Object Animator, we set our own updates to element attributes ~a few lines more code, but it seems to improve flexibility~
Let's take another example. If I want the spherical parabolic motion [to achieve parabolic effect, horizontal direction 100px/s, vertical direction acceleration 200px/s*s], it seems only related to time, but according to the change of time, the lateral and vertical movement rates are different, how can we achieve it? It's time to rewrite TypeValue, because we need to return two values to the object, the current position of x and the current position of y, as time changes.
Code:
[java] view plain copy
/** * parabola * @param view */ public void paowuxian(View view) { ValueAnimator valueAnimator = new ValueAnimator(); valueAnimator.setDuration(3000); valueAnimator.setObjectValues(new PointF(0, 0)); valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.setEvaluator(new TypeEvaluator<PointF>() { // fraction = t / duration @Override public PointF evaluate(float fraction, PointF startValue, PointF endValue) { Log.e(TAG, fraction * 3 + ""); // x direction 200px/s, y direction 0.5 * 10 * t PointF point = new PointF(); point.x = 200 * fraction * 3; point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3); return point; } }); valueAnimator.start(); valueAnimator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { PointF point = (PointF) animation.getAnimatedValue(); mBlueBall.setX(point.x); mBlueBall.setY(point.y); } }); }
As you can see, because ofInt,ofFloat and so on can not be used, we customize a TypeValue, each time according to the current time to return a PointF object. (The difference between PointF and Point is that the unit of x,y is float, one is int;RectF,Rect is also) PointF contains the current location of x,y - and then we get in the monitor, dynamically set properties:
Design sketch:
There are two iron balls falling on the ground at the same time. Yes, I should do two balls. If the physical formula is wrong, you should not see it.
Customized generic type Evaluator can design a Bean according to its own needs.
Okay, we have explained how Value Animator and Object Animator implement animation separately; the difference between them; how to use part of the API to update their own properties to achieve the effect; how to customize Type Evaluator to achieve our needs; but we have not talked about how to design interpolation, in fact, I think that the default string of implementation classes of this interpolation is enough ~~very few, and will design a super by ourselves. Grade metamorphic ~Hmm ~So: slightly.
5. Monitoring Animation Events
For animation, usually some auxiliary effects, such as I want to delete an element, I may hope it is a fade effect, but ultimately to delete, not because you have no transparency, but also occupy a position, so we need to know how the animation ends.
So we can add an animation monitor:
[java] view plain copy
public void fadeOut(View view) { ObjectAnimator anim = ObjectAnimator.ofFloat(mBlueBall, "alpha", 0.5f); anim.addListener(new AnimatorListener() { @Override public void onAnimationStart(Animator animation) { Log.e(TAG, "onAnimationStart"); } @Override public void onAnimationRepeat(Animator animation) { // TODO Auto-generated method stub Log.e(TAG, "onAnimationRepeat"); } @Override public void onAnimationEnd(Animator animation) { Log.e(TAG, "onAnimationEnd"); ViewGroup parent = (ViewGroup) mBlueBall.getParent(); if (parent != null) parent.removeView(mBlueBall); } @Override public void onAnimationCancel(Animator animation) { // TODO Auto-generated method stub Log.e(TAG, "onAnimationCancel"); } }); anim.start(); }
This allows you to monitor the start, end, cancel, repeat and other events of the animation ~But sometimes it feels like I just need to know the end. I can't accept such a long code, so you can use the Animator Listener Adapter.
[java] view plain copy
anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { Log.e(TAG, "onAnimationEnd"); ViewGroup parent = (ViewGroup) mBlueBall.getParent(); if (parent != null) parent.removeView(mBlueBall); } });
AnimatorListener Adapter inherits the AnimatorListener interface and implements all methods empty~
Design sketch:
animator also has cancel() and end() methods: cancel animation stops immediately and stops at the current location; end animation goes directly to the final state.
6. Use of AnimatorSet
Example:
Layout file:
[html] view plain copy
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/id_container" > <ImageView android:id="@+id/id_ball" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:src="@drawable/bol_blue" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="horizontal" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="togetherRun" android:text="Simple multi-animation Together" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="playWithAfter" android:text="Multi-animation is executed in sequence" /> </LinearLayout> </RelativeLayout>
Keep playing ball~
Code:
[java] view plain copy
package com.example.zhy_property_animation; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.animation.LinearInterpolator; import android.widget.ImageView; public class AnimatorSetActivity extends Activity { private ImageView mBlueBall; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.anim_set); mBlueBall = (ImageView) findViewById(R.id.id_ball); } public void togetherRun(View view) { ObjectAnimator anim1 = ObjectAnimator.ofFloat(mBlueBall, "scaleX", 1.0f, 2f); ObjectAnimator anim2 = ObjectAnimator.ofFloat(mBlueBall, "scaleY", 1.0f, 2f); AnimatorSet animSet = new AnimatorSet(); animSet.setDuration(2000); animSet.setInterpolator(new LinearInterpolator()); //Simultaneous execution of two animations animSet.playTogether(anim1, anim2); animSet.start(); } public void playWithAfter(View view) { float cx = mBlueBall.getX(); ObjectAnimator anim1 = ObjectAnimator.ofFloat(mBlueBall, "scaleX", 1.0f, 2f); ObjectAnimator anim2 = ObjectAnimator.ofFloat(mBlueBall, "scaleY", 1.0f, 2f); ObjectAnimator anim3 = ObjectAnimator.ofFloat(mBlueBall, "x", cx , 0f); ObjectAnimator anim4 = ObjectAnimator.ofFloat(mBlueBall, "x", cx); /** * anim1,anim2,anim3 Simultaneous execution * anim4 Then execute */ AnimatorSet animSet = new AnimatorSet(); animSet.play(anim1).with(anim2); animSet.play(anim2).with(anim3); animSet.play(anim4).after(anim3); animSet.setDuration(1000); animSet.start(); } }
Write two effects:
First: Use playTogether to execute both animations at the same time, and playSequentially, of course, in turn.~~
Second: If we have a bunch of animations, how to use the code to control the sequence, such as 1, 2 at the same time; 3 after 2; 4 before 1 ~ is the effect of 2.
One thing to note: animSet.play().with(); also supports chain programming, but don't think about crazy points, such as animSet.play(anim1).with(anim2).before(anim3).before(anim5); this is not possible, the system will not determine the order according to the long string you write, so please write a few more lines according to the above example: animSet.play(anim1).with(anim2).before(anim3).before(anim5).
Design sketch:
OK, because of the space ~~there's still some knowledge about attribute animation:
1. Creating attribute animation in xml file
2. Layout Animation
3. The animate method of View, etc.
So consider writing the next article, but that's the core function.~~
By the way, if you use the SDK below 11, please import the Nineold and ROIDS animation library. The usage is basically the same.~