Zero, Preface:Knowledge points
Understanding and using ValueAnimator
Customizing and using the TypeEvaluator
Custom and usage of TimeInterpolator
Path in combination with Animator
ObjectAnimator customization and use
The use of TimeAnimator
AnimatorSet Use of an animation set
Introduction and use of listeners of the Animator family
Use of the Animator family in XML
The Animator system is not complex, but the internal implementation is quite complex. Many classes have been buried in the bottom for years, not to see the light of day such as: PropertyValuesHolder and its subclasses, Keyframes family, Keyframe family, KeyframeSet family today tried to read the source code, basically read the muddled, the general idea is to grasp
Section 1: Use of ValueAnimator
First, simple use
0.Animator Family simple understanding:
Animator is an abstract class. It is not available. You can only find its subclasses
1. Here is the simplest use of ValueAnimator
ValueAnimator animator = ValueAnimator.ofInt(0, 10);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.e(TAG, animation.getAnimatedValue()+"-"); }}); animator.start();Copy the code
Print result analysis:
2018-12-26 12:04:09.290 ~ 2018-12-26 12:04:09.584---->584-290=294 The default duration is 300(defined in the source code), basically the same, The basic purpose of ValueAnimator is to constantly call back to the onAnimationUpdate method during this time and to change the animation value from a predetermined range of 0 to 10Copy the code
The 2018-12-26 12:04:09. 290, 2001-2001 / com. Toly1994. Animator_test E/MainActivity: 0-2018-12-26 12:04:09. 335, 2001-2001 / com. Toly1994. Animator_test E/MainActivity: 0-2018-12-26 12:04:09. 351, 2001-2001 / com. Toly1994. Animator_test E/MainActivity: 1-2018-12-26 12:04:09. 373, 2001-2001 / com. Toly1994. Animator_test E/MainActivity: 1-2018-12-26 12:04:09. 412, 2001-2001 / com. Toly1994. Animator_test E/MainActivity: 3 - the 2018-12-26 12:04:09. 439, 2001-2001 / com. Toly1994. Animator_test E/MainActivity: 5-2018-12-26 12:04:09. 450, 2001-2001 / com. Toly1994. Animator_test E/MainActivity: 5-2018-12-26 12:04:09. 468, 2001-2001 / com. Toly1994. Animator_test E/MainActivity: 6-2018-12-26 12:04:09. 484, 2001-2001 / com. Toly1994. Animator_test E/MainActivity: 7-2018-12-26 12:04:09. 502, 2001-2001 / com. Toly1994. Animator_test E/MainActivity: 8-2018-12-26 12:04:09. 517, 2001-2001 / com. Toly1994. Animator_test E/MainActivity: 8-2018-12-26 12:04:09. 534, 2001-2001 / com. Toly1994. Animator_test E/MainActivity: 9-2018-12-26 12:04:09. 568. 2001-2001 / com toly1994. Animator_test E/MainActivity: 9-2018-12-26 12:04:09. 584. 2001-2001 / com toly1994. Animator_test E/MainActivity: 10 -Copy the code
2. Ideas derived from it
1). Constantly call the onAnimationUpdate callback 2). You can get different values that change regularly in the custom View onAnimationUpdate to refresh the interface and dynamically change the values
/** * Author: Zhang Feng Jiete Lie <br/> * Time: 2018/12/26 0026:7:50<br/> * Email: [email protected]<br/> * Description: Public class AnimatorView extends View {private static final String TAG ="AnimatorView"; private Paint mPaint; Private int mRadius = 100; Private ValueAnimator mAnimator; private ValueAnimator mAnimator; Public AnimatorView(Context Context) {this(Context, null); } public AnimatorView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } private voidinit() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(0xff94E1F7);
mAnimator = ValueAnimator.ofInt(100, 300);
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mRadius= (int) animation.getAnimatedValue(); invalidate(); }}); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.translate(400, 400); DrawCircle (0, 0, mRadius, mPaint); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) {case MotionEvent.ACTION_DOWN:
Log.e(TAG, "onTouchEvent: "); mAnimator.start(); // Click to open the animationbreak;
case MotionEvent.ACTION_UP:
}
returnsuper.onTouchEvent(event); }}Copy the code
It’s a simple matter of replacing printouts with a refresh view, and the radius is constantly changing
3. Common configuration
Take a look at the difference between RESTART(default) and REVERSE
RESTART | REVERSE |
---|---|
mAnimator.setStartDelay(1000); // Set delay manimator.setrepeatCount (2); // Set the number of repetitions. // manimator.setrepeatMode (valueAnimator.restart); 100->300 100->300 manimator.setrepeatMode (valueAnimator.reverse); Manimator.setduration (1000); manimator.setduration (1000); // Set the durationCopy the code
Second,ofArgb
withofObject
Color change | Color size |
---|---|
Step 1 Change color:ofArgb
Pass in two colors (start color and end color)
mColorAnimator = ValueAnimator.ofArgb(0xff94E1F7, 0xffF35519); mColorAnimator.setDuration(500); / / set the length mColorAnimator. SetRepeatCount (1); / / set the number of repeat mColorAnimator. SetRepeatMode (ValueAnimator. REVERSE); mColorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mPaint.setColor((Integer) animation.getAnimatedValue()); invalidate(); }});Copy the code
2. How to change both size and color:
ValueAnimator.ofObject
+TypeEvaluator
2.1 First define a class to host the data: Ball(for the sake of brevity, use the public property)
public class Ball {
public int color;
public int r;
public Ball() { } public Ball(int r, int color) { this.color = color; this.r = r; }}Copy the code
Creating a TypeEvaluator
A TypeEvaluator is used to determine how various properties of an object change. Here is an example: Where fraction is the fraction, startValue and endValue are the states of the start and end objects, respectively
public class BallEvaluator implements TypeEvaluator {
@Override
public Object evaluate(floatfraction, Object startValue, Object endValue) { Ball start = (Ball) startValue; Ball end = (Ball) endValue; Ball Ball = new Ball(); R = (int) (start.r + fraction *(end.r - start.r)); // How the color gradient? ball.color = evaluateColor(fraction, start.color, end.color);returnnull; } /** * evaluateColor(evaluateColor);float fraction, Object startValue, Object endValue) {
int startInt = (Integer) startValue;
floatStartA = ((startInt >> 24) &0xff) / 255.0f;floatStartR = ((startInt >> 16) &0xff) / 255.0f;floatStartG = ((startInt >> 8) &0xff) / 255.0f;floatStartB = (startint&0xff) / 255.0f; int endInt = (Integer) endValue;floatEndA = ((endInt >> 24) &0xff) / 255.0f;floatEndR = ((endInt >> 16) &0xff) / 255.0f;floatEndG = ((endInt >> 8) &0xff) / 255.0f;floatEndB = (endInt &0xff) / 255.0f; // convert from sRGB to linear startR = (float() Math. Pow startR, 2.2); startG = (float() Math. Pow startG, 2.2); startB = (float() Math. Pow startB, 2.2); endR = (float() Math. Pow endR, 2.2); endG = (float() Math. Pow endG, 2.2); endB = (float() Math. Pow endB, 2.2); // compute the interpolated colorin linear space
float a = startA + fraction * (endA - startA);
float r = startR + fraction * (endR - startR);
float g = startG + fraction * (endG - startG);
float b = startB + fraction * (endB - startB);
// convert back to sRGB inThe [0..255] range a = a * 255.0f; r = (float) math.pow (r, 1.0/2.2) * 255.0f; g = (float) math.pow (g, 1.0/2.2) * 255.0f; b = (float) math.pow (b, 1.0/2.2) * 255.0f;returnMath.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b); }}Copy the code
Look at how the gradient color in the source: ArgbEvaluator getInstance () you can see a computing method of color with bai direct kao used to (I)
public static ValueAnimator ofArgb(int... values) {
ValueAnimator anim = new ValueAnimator();
anim.setIntValues(values);
anim.setEvaluator(ArgbEvaluator.getInstance());
returnanim; } -- -- -- - > [color method to calculate the evaluate] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- public Object evaluate (floatFraction, Object startValue, Object endValue) {// Calculate the color method details...... }Copy the code
3. Specify the equation motion of the curve using the estimator
The equation is a conic :y=x*x/800 but you can define what you like
public class Ball {
public int color;
public int r;
public int x;
public int y;
public Ball() { } public Ball(int r, int color) { this.color = color; this.r = r; } public Ball(int r, int color, int x, int y) { this.color = color; this.r = r; this.x = x; this.y = y; }}Copy the code
Evaluator modification:
public class BallEvaluator implements TypeEvaluator {
@Override
public Object evaluate(floatfraction, Object startValue, Object endValue) { Ball start = (Ball) startValue; Ball end = (Ball) endValue; Ball ball = new Ball(); ball.color = evaluateColor(fraction, start.color, end.color); ball.r = (int) (start.r + fraction * (end.r - start.r)); ball.x = (int) (start.x + fraction * (end.x - start.x)); ball.y= ball.x*ball.x/800; // The value of y depends on xreturnball; }}Copy the code
AnimatorView
public class AnimatorView extends View {
private static final String TAG = "AnimatorView";
private Paint mPaint;
private int mRadius = 50;
private int dx;
private int dy;
private ValueAnimator mAnimator;
private ValueAnimator mColorAnimator;
private ValueAnimator mObjAnimator;
public AnimatorView(Context context) {
this(context, null);
}
public AnimatorView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(0xff94E1F7); Ball startBall = new Ball(50, 0xff94E1F7,0,0); Ball endBall = new Ball(100, 0xffF35519,500,1000); mObjAnimator = ValueAnimator.ofObject(new BallEvaluator(), startBall, endBall); mObjAnimator.setRepeatMode(ValueAnimator.REVERSE); 100->300 300->100 mobjAnimator.setduration (1000); / / set the length mObjAnimator. SetRepeatCount (1); / / set the number of repeat mObjAnimator. SetRepeatMode (ValueAnimator. REVERSE); mObjAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Ball ball = (Ball) animation.getAnimatedValue(); mRadius = ball.r; mPaint.setColor(ball.color); dx=ball.x; dy=ball.y; Log.e(TAG,"onAnimationUpdate: "+dx+":"+dy); invalidate(); }}); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.translate(dx, dy); canvas.drawCircle(mRadius, mRadius, mRadius, mPaint); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) {case MotionEvent.ACTION_DOWN:
mObjAnimator.start();
break;
case MotionEvent.ACTION_UP:
}
returnsuper.onTouchEvent(event); }}Copy the code
This is the basic routine. With ofObject, properties can be changed at will. Are you still afraid of animation? In fact, ofInt,ofFloat, and ofArgb just apply the built-in evaluator, which is essentially no different from ofObject. It can be viewed as a simple version of ofObject with a single attribute
Three, interpolator
If the evaluator TypeEvaluator tells you how to run, then the interpolator tells you how fast to run
1. Custom interpolator: Sin type fast then slow
In this case, the input changes from 0 to 1, and the interpolator changes the input
public class D_Sin_Inter implements TimeInterpolator {
@Override
public float getInterpolation(floatInput) {// Input is a uniform value from 0 to 1 // a uniform value from 0 to PI/2float rad = (float) (Math.PI/2 * input); // Return the sine of this radian -- the sine curve grows slower and slower between 0 and PI/2, and the ball moves slower and slowerreturn (float) (Math.sin(rad)); }}Copy the code
2. Custom interpolator: Sin type first full and then fast
public class A_Sin_Inter implements TimeInterpolator {
@Override
public float getInterpolation(floatInput) {// Input is a uniform value from 0 to 1 // a uniform value from 0 to PI/2float rad = (float) (Math.PI/2 * input+Math.PI/2); // Return the sine of this radian -- the sine curve decreases faster and faster in PI/2~PIreturn (float) (1-(Math.sin(rad))); // Return 1-}}Copy the code
3. Custom interpolator: Log
/** * Author: Zhang Feng Jiete Lay <br/> * Time: 2018/12/26 0026:20:41<br/> * Email: [email protected]<br/> * Description: Public class D_Log_Inter implements TimeInterpolator {@override publicfloat getInterpolation(float input) {
return (float) (Math.log10(1 + 9 * input)); }}Copy the code
Interpolator is actually based on input processing. The time flow (each refresh interval) is basically constant, and the input uniformly changes from 0 to 1. It is mapped to a set of corresponding relations through input. The return value is y, which is used in code (D_Sin_Inter) LinearInterpolator x=y, but it’s the same thing
4. Elegant implementation test code
Just add them to the name array and interpolator array, and the rest will be handled automatically
public class AnimatorInterView extends View {
private static final String TAG = "AnimatorView";
private Paint mPaint;
private int mRadius = 50;
private int dx[];
private String[] mStrings;
private TimeInterpolator[] mInterpolators;
public AnimatorInterView(Context context) {
this(context, null);
}
public AnimatorInterView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(0xff94E1F7);
mPaint.setTextSize(40);
mStrings = new String[]{"Linear"."Bounce"."AOI"."OI"."D_sin"."D_log"."A_sin"."A_log"}; mInterpolators = new TimeInterpolator[]{ new LinearInterpolator(), new BounceInterpolator(), new AnticipateOvershootInterpolator(), new OvershootInterpolator(), new D_Sin_Inter(), new D_Log_Inter(), new A_Sin_Inter()}; dx = new int[mInterpolators.length]; } private ValueAnimator createAnimator(int index, TimeInterpolator interpolator) { ValueAnimator mAnimator = ValueAnimator.ofInt(0, 800); mAnimator.setRepeatCount(1); Manimator.setrepeatmode (valueAnimator.reverse); Manimator.setduration (3000); manimator.setduration (3000); / / set the length mAnimator. SetInterpolator (interpolator); mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { dx[index] = (int) animation.getAnimatedValue(); invalidate(); }});return mAnimator;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < dx.length; i++) {
canvas.translate(0, 120);
mPaint.setColor(0xff94E1F7);
canvas.drawCircle(mRadius + dx[i], mRadius, mRadius, mPaint);
mPaint.setColor(0xff000000);
mPaint.setStrokeWidth(4);
canvas.drawLine(mRadius, mRadius, 800 + mRadius, mRadius, mPaint);
canvas.drawText(mStrings[i], 800 + 3 * mRadius, mRadius, mPaint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
for (int i = 0; i < mInterpolators.length; i++) {
createAnimator(i, mInterpolators[i]).start();
}
break;
case MotionEvent.ACTION_UP:
}
returnsuper.onTouchEvent(event); }}Copy the code
Interlude: A combination of paths and animators
The core is to use PathMeasure and DashPathEffect to control the length of the Path. For details, see everything you Know and Don’t know about Path on Android
/** * Author: Zhang Feng Jiete Lie <br/> * Time: 2018/12/26 0026:7:50<br/> * Email: [email protected]<br/> * Description: Animator and Path */ public Class AnimatorPathView Extends View {private static final String TAG ="AnimatorView";
private Paint mPaint;
private Path mPath;
private PathMeasure pathMeasure;
public AnimatorPathView(Context context) {
this(context, null);
}
public AnimatorPathView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(0xff94E1F7); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(10); mPaint.setStrokeJoin(Paint.Join.ROUND); MPath = new Path(); mPath = nStarPath(mPath, 8, 250, 160); PathMeasure = new pathMeasure (mPath,false);
}
private ValueAnimator createAnimator() { ValueAnimator mAnimator = ValueAnimator.ofInt(0, 800); mAnimator.setRepeatCount(1); Manimator.setrepeatmode (valueAnimator.reverse); Manimator.setduration (3000); manimator.setduration (3000); / / set the length mAnimator. SetInterpolator (new AnticipateOvershootInterpolator ()); mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
floatvalue = animation.getAnimatedFraction(); DashPathEffect effect = new DashPathEffect(new)float[]{ pathMeasure.getLength(), pathMeasure.getLength()}, value * pathMeasure.getLength()); mPaint.setPathEffect(effect); invalidate(); }});return mAnimator;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(250, 250);
canvas.drawPath(mPath, mPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
createAnimator().start();
break;
case MotionEvent.ACTION_UP:
}
returnsuper.onTouchEvent(event); } @param R @param R @param R @param R @param R @param R @param R @param R @param R @param R @param R @param R @param RreturnPublic static Path nStarPath(Path Path, int num,float R, float r) {
float perDeg = 360 / num;
float degA = perDeg / 2 / 2;
float degB = 360 / (num - 1) / 2 - degA / 2 + degA;
path.moveTo((float) (Math.cos(rad(degA)) * R), (float) (-Math.sin(rad(degA)) * R));
for (int i = 0; i < num; i++) {
path.lineTo(
(float) (Math.cos(rad(degA + perDeg * i)) * R),
(float) (-Math.sin(rad(degA + perDeg * i)) * R));
path.lineTo(
(float) (Math.cos(rad(degB + perDeg * i)) * r),
(float) (-Math.sin(rad(degB + perDeg * i)) * r));
}
path.close();
returnpath; } /** * convert Angle to radians ** @param deg Angle * @return*/ public staticfloat rad(float deg) {
return (float) (deg * Math.PI / 180); }}Copy the code
Section two: son of ValueAnimatorObjectAnimator and TimeAnimator
:
ObjectAnimator animates “Xxx” properties that have a setXxx method. The ObjectAnimator animates “Xxx” properties that have a setXxx method. The ObjectAnimator animates “Xxx” properties that have a setXxx method
1. Test the built-in properties of View
1. Getting Started — Down example:
private ObjectAnimator mMoveDown; // Move the animation downCopy the code
MMoveDown = ObjectAnimator// Create an instance //(View, property name, initialization value, end value).offloat (this,"translationY", 0, 300) .setDuration(1000); // Set frequentlyCopy the code
@override // protected void onDraw(Canvas) {super.ondraw (Canvas); canvas.drawCircle(50, 50, 50, mPaint); }Copy the code
mMoveDown.start(); // Start the animationCopy the code
If you put that in the background, you can see that the whole View has changed.
2. Common attributes:
The property name | demo | explain |
---|---|---|
alpha | Transparency 1 to 0 | |
translationX | It’s moving in the X direction | |
translationY | Y direction | |
rotation | Rotation (default View center point) | |
rotationX | X axis rotation (default View center horizontal axis) | |
rotationY | Y axis rotation (default View center vertical axis) | |
scaleX | X scale | |
scaleY | Y scale |
3. Setting the center point of rotation and zooming:
setPivotX(200);
setPivotY(200);
Copy the code
4. Multiple parameters (The multi-parameter case applies to the Animator family
)
360 360-0 – > – > 0 0 – – > 90
.ofFloat(this, "rotation", 0, 360360,0,0,90)Copy the code
Custom ObjectAnimator property
The built-in properties are just the usual ones, but we can also customize our own
1. Customize the circle size animation
The redraw method must be called with a setXxx method with the property name XXX
public void setRadius(int radius) { mRadius = radius; invalidate(); // Remember to redraw}Copy the code
ObjectAnimator// create an instance //(View, property name, initialization value, end value).fint (this,"Radius", 100, 50100,20,100). SetDuration (3000); // Set frequentlyCopy the code
2. Custom color animations
public void setColor(int color) { mColor = color; mPaint.setColor(mColor); invalidate(); // Remember to redraw}Copy the code
ColorAnimator = ObjectAnimator// Create instance //(View, property name, initialization value, end value).ofint (this,"color", 0xff0000ff, 0xffF2BA38, 0xffDD70BC) .setDuration(3000); colorAnimator.setEvaluator(new ArgbEvaluator()); // Color estimatorCopy the code
3. What is the difference between ValueAnimator and ObjectAnimator?
1.ValueAnimator needs to manually add listening, manually obtain ValueAnimator data, manually write the change logic 2.ObjectAnimator can not be updated listening, the core in 'setXxx 'in, that is, each update will go by itselfset3. The flexibility of ValueAnimator is better, after all, you can do it yourself, you can imagine how to play it. 4set5. Generally speaking, ObjectAnimator is oriented to application (concise and fast), ValueAnimator is oriented to operation (flexible and changeable).Copy the code
Third, TimeAnimator
This class is 100 lines of code, and almost half of it is comments. It inherits from ValueAnimator and is the apple of the Animator family, but it is very pure and focused and wants to do only one thing: provide a time stream (each 16 or 17ms callback method).
mAnimator = new TimeAnimator(); / / / / (himself, the total length, interval between each callback). MAnimator setTimeListener ((animation, totalTime, deltaTime) - > {the e (the TAG,"totalTime:" + totalTime + ", deltaTime:" + deltaTime);
if(totalTime > 300) { animation.pause(); }});Copy the code
Running result:
TimeAnimatorView: totalTime:0, deltaTime:0 TotalTime :2, deltaTime:2 TimeAnimatorView: totalTime:19, deltaTime:17 TimeAnimatorView: totalTime:36, deltaTime:17 TotalTime :52, deltaTime:16 2018-12-27 10:09:35.118 E/TimeAnimatorView: TimeAnimatorView: totalTime:69, deltaTime:17 TotalTime :86, deltaTime:17 2018-12-27 10:09:35.151 E/TimeAnimatorView: TotalTime :102, deltaTime:16 2018-12-27 10:09:35.167 E/TimeAnimatorView: TotalTime :119, deltaTime:17 2018-12-27 10:09:35.184 E/TimeAnimatorView: TotalTime :136, deltaTime:17 2018-12-27 10:09:35.200e /TimeAnimatorView: TotalTime :152, deltaTime:16 2018-12-27 10:09:35.218 E/TimeAnimatorView: TimeAnimatorView: totalTime: 169e, deltaTime:17 TotalTime :186, deltaTime:17 2018-12-27 10:09:35.251 E/TimeAnimatorView: TotalTime :202, deltaTime:16 2018-12-27 10:09:358.268 E/TimeAnimatorView: TotalTime :219, deltaTime:17 2018-12-27 10:09:35.284e /TimeAnimatorView: TimeAnimatorView: totalTime: 236e /TimeAnimatorView: TotalTime :252, deltaTime:16 2018-12-27 10:09:35.318 E/TimeAnimatorView: TotalTime :269, deltaTime:17 2018-12-27 10:09:35.334 E/TimeAnimatorView: TimeAnimatorView: totalTime:303, deltaTime:17Copy the code
So that’s basically the end of the ValueAnimator story (there are a few more listeners, and finally together)
Fourth, the AnimatorSet
The AnimatorSet itself is not difficult to assemble from the previous animations
1. AnimatorSet in Builder mode
Each animation is a Node in the AnimatorSet. To process the relationship between the current Node and the inserted Node, look at the following set of animations:
MSet --> translationX --> translationX. Play (translationX)// translationX. With (alpha)// Tance.after (radiusAnimator)// radiusAnimator. / / discolorationCopy the code
Test source code:
public class AnimatorSetView extends View {
private static final String TAG = "AnimatorView";
private Paint mPaint;
private int mRadius = 50;
private int mColor = 50;
private ObjectAnimator colorAnimator;
private ObjectAnimator radiusAnimator;
ObjectAnimator translationX;
ObjectAnimator alpha;
private AnimatorSet mSet;
public AnimatorSetView(Context context) {
this(context, null);
}
public AnimatorSetView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(0xff94E1F7); mSet = new AnimatorSet(); TranslationX = perspectiveAnimator translationX = perspectiveAnimator translationX = perspectiveAnimator translationX = PerspectiveAnimator translationX = PerspectiveAnimator translationX = PerspectiveAnimator translationX = PerspectiveAnimator translationX = PerspectiveAnimator translationX = PerspectiveAnimator"translationX", 0, 300, 150, 100, 20, 100) .setDuration(3000); // set alpha = ObjectAnimator// create an instance //(View, property name, initialization value, end value).offloat (this,"alpha", 1, 0.5f, 1, 0, 1).setduration (3000); // radiusAnimator = ObjectAnimator// Create an instance //(View, property name, initialization value, end value).fint (this,"Radius", 50, 100, 50, 100, 20, 100) .setDuration(3000); ColorAnimator = ObjectAnimator// Create an instance //(View, property name, initialization value, end value).fint (this,"color", 0xff0000ff, 0xffF2BA38, 0xffDD70BC) .setDuration(3000); colorAnimator.setEvaluator(new ArgbEvaluator()); // Radius --> translationX --> translationX. With (alpha).after(radiusAnimator).before(colorAnimator); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(mRadius, mRadius, mRadius, mPaint); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) {case MotionEvent.ACTION_DOWN:
mSet.start();
break;
case MotionEvent.ACTION_UP:
}
return super.onTouchEvent(event);
}
public void setRadius(int radius) {
mRadius = radius;
setMeasuredDimension(mRadius * 2, mRadius * 2); invalidate(); // Remember to redraw} public voidsetColor(int color) { mColor = color; mPaint.setColor(mColor); invalidate(); // Remember to redraw}}Copy the code
2.AnimatorSet itself method:
Just as the name suggests: exercise together or in batches
mSet.playTogether(translationX,alpha,radiusAnimator,colorAnimator);
mSet.playSequentially(translationX,alpha,radiusAnimator,colorAnimator);
Copy the code
Four, the monitoring of Animator:
An Animator has two internal interfaces, AnimatorListener and AnimatorPauseListener. AnimatorListenerAdapter is an empty implementation class for two interfaces, the standard adapter pattern. ValueAnimator as a child has its own interface, AnimatorUpdateListener
1.AnimatorListener
: Animation monitor
The listener in the Animator can also be used by both children
Void onAnimationStart(Animator animation); Void onAnimationEnd(Animator animation); Void onAnimationCancel(Animator animation); Void onAnimationRepeat(Animator animation);Copy the code
2. Animation test
Start with green –> Repeat with random color –> Cancel with size to 50–> End with blue
mTranslationX = translationX();
mTranslationX.setRepeatMode(ValueAnimator.REVERSE);
mTranslationX.setRepeatCount(ValueAnimator.INFINITE);
mTranslationX.addListener(new Animator.AnimatorListener() {@override public void onAnimationStart(Animator animation) {// Start with greensetColor(Color.GREEN); } @override public void onAnimationEnd(Animator animation) {// Set the end to bluesetColor(Color.BLUE); } @override public void onAnimationCancel(Animator animation) {// Cancel when the size is 50setCircleR(50); } @override public void onAnimationRepeat(Animator animation) {// Set to random color when repeatingsetColor(ColUtils.randomColor()); }}); mTranslationX.start();Copy the code
mTranslationX.cancel(); // Cancel the animationCopy the code
3,AnimatorPauseListener
: Animation pause listening
Void onAnimationPause(Animator animation); Void onAnimationResume(Animator animation);Copy the code
The effect is as follows: Click on motion, swipe right to pause the color and turn yellow, and slide down to restore the color and turn blue
mTranslationX.addPauseListener(new Animator.AnimatorPauseListener() {
@Override
public void onAnimationPause(Animator animation) {
setColor(Color.YELLOW); } @override public void onAnimationResume(Animator animation) {setColor(Color.BLUE); // Restore blue}});Copy the code
4,AnimatorUpdateListener
: ValueAnimator A series of proprietary monitors
Void onAnimationUpdate(ValueAnimator Animation);Copy the code
The effect is as follows: Each update is to link the radius and displacement
mTranslationX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCircleR = (Float) animation.getAnimatedValue();
invalidate();
}
});
Copy the code
Use of the Animator family in XML:
Create the: animator folder under res
1. The Animator tag
Using the animator tag directly also feels a bit cumbersome, so take a look here
In the XML attribute | meaning | In the code |
---|---|---|
duration | Duration of play | setDuration() |
valueType | Parameter Value Type | ofXXX |
valueFrom | The initial value | OfXXX (para. 1) |
valueTo | The end value | OfXXX (para. 2) |
startOffset | Time delay | startDelay() |
repeatCount | Repeat the number | setRepeatCount() |
interpolator | interpolator | setRepeatMode() |
1.1. The animator. XML
<? xml version="1.0" encoding="utf-8"? > <animator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:repeatCount="2"
android:repeatMode="reverse"
android:startOffset="1000"
android:valueFrom="0dp"
android:valueType="floatType"
android:valueTo="200dp">
</animator>
Copy the code
1.2. The layout
<? xml version="1.0" encoding="utf-8"? > <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<View
android:id="@+id/id_btn_go"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginStart="24dp"
android:layout_marginTop="32dp"
android:background="#3ED7FA"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
Copy the code
1.3. Use:MainActivity
Get ValueAnimator from Xml, and then do it yourself, which feels a bit cumbersome
View button = findViewById(R.id.id_btn_go);
ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(this, R.animator.animator);
animator.addUpdateListener(anim->{
float animatedValue = (float) anim.getAnimatedValue();
button.setTranslationX(animatedValue);
});
button.setOnClickListener((v)->{
animator.start();
});
Copy the code
2.set
withobjectAnimator
The label
ObjectAnimator has one more propertyName property. The rest are consistent
2.1set_obj_animator.xml
<? xml version="1.0" encoding="utf-8"? > <set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="sequentially">
<objectAnimator
android:duration="1500"
android:propertyName="rotationY"
android:valueFrom="0"
android:valueTo="180"/>
<objectAnimator
android:duration="1500"
android:propertyName="alpha"
android:valueFrom="0.3 f"
android:valueTo="1f"/>
<objectAnimator
android:duration="1500"
android:propertyName="translationX"
android:valueFrom="0"
android:valueTo="180dp"/>
</set>
Copy the code
2.2: used in code
View button = findViewById(R.id.id_btn_go);
Animator set_obj = AnimatorInflater.loadAnimator(this, R.animator.set_obj_animator);
et_obj.setTarget(button);
button.setOnClickListener((v)->{
set_obj.start();
});
Copy the code
3, take a last look at me bigobjectAnimator
Transformation path
The complete guide to Vector maps in Android resource Res (with analysis of the SVG-path command)
Arrows: M8,50, L100,0 M0,47, L40,40 M0,52 L40-40 Menu: M0,50, L80,0 M0,80, L80,0 M0,20 L80 0Copy the code
The path of deformation | Deformation + rotation |
---|---|
1. Put the two path strings into string.xml
You can write directly, but it’s not easy to reuse
<resources>
<string name="app_name">test</string>
<string name="path_from"</string> <string name="path_to"</string> </resources> </resources>Copy the code
2. Vector diagram: path_test.xml
<? xml version="1.0" encoding="utf-8"? > <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="100"
android:viewportHeight="100">
<group
android:translateX="4"
android:translateY="4">
<path
android:pathData="M0, A30 0, 50,90,0,1,50,50"
android:strokeWidth="4"
android:strokeColor="@color/black"/>
</group>
</vector>
Copy the code
3. Rotate animation: rotation_animator.xml
<? xml version="1.0" encoding="utf-8"? > <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="180"/>
Copy the code
4. Path animation: path_animator.xml
<? xml version="1.0" encoding="utf-8"? > <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:interpolator="@android:interpolator/linear"
android:propertyName="pathData"
android:valueFrom="@string/path_from"
android:valueTo="@string/path_to"
android:valueType="pathType"/>
Copy the code
5. Vector drawing file:icon_path.xml
<? xml version="1.0" encoding="utf-8"? > <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="100"
android:viewportHeight="100">
<group android:name="container"
android:translateX="8"
android:pivotX="50"
android:scaleY="0.8"
android:scaleX="0.8"
android:pivotY="50">
<path
android:name="alpha_anim"
android:pathData="@string/path_from"
android:strokeWidth="8"
android:strokeColor="# 000"/>
</group>
</vector>
Copy the code
6. Integrate animation: anima_path.xml
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/icon_path">
<target
android:name="alpha_anim"
android:animation="@animator/path_animator"/>
<target
android:name="container"
android:animation="@animator/rotation_animator">
</target>
</animated-vector>
Copy the code
7. Use animations:
<ImageView
android:id="@+id/id_iv"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/anima_path"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
Copy the code
Drawable Drawable = midiv.getDrawable (); Drawable Drawable = midiv.getDrawable ();if (drawable instanceof Animatable){
((Animatable) drawable).start();
}
Copy the code
Ok, that’s it, you can customize both paths as much as you want, but you have to make sure that the instructions for both paths are the same, otherwise it will crash
Postscript: Jie wen standard
1. Growth record and Errata of this paper
Program source code | The date of | note |
---|---|---|
V0.1 – making | 2018-12-27 | Android Animator family Guide |
2. More about me
Pen name | hobby | ||
---|---|---|---|
Zhang Feng Jie te Li | 1981462002 | zdl1994328 | language |
My lot | My Jane books | I’m the nuggets | Personal website |
3. The statement
1—- this article is originally written by Zhang Feng Jetelie, please note 2—- all programming enthusiasts are welcome to communicate with each other 3—- personal ability is limited, if there is any error, you are welcome to criticize and point out, will be modest to correct 4—- See here, I thank you here for your love and support