Learn more about Android animation

1, PropertyValuesHolder Reading this article ...
1. Understanding and use
2. Methods and parameters
1. Understanding and use
2. Methods and parameters
3. Frame operation
1. Understanding and use
2. Parameters and methods
1. Initialization
2. Function call
1, PropertyValuesHolder

Reading this article requires the foundation of Android attribute animation in the previous article, so that you can understand what to say next.

1. Understanding and use

PropertyValuesHolder is a method similar to ObjectAnimation, but with one target missing, it is the control to be executed. Look at the normal usage: all holders will be executed at the same time

public void doPropertyValuesHolder(){ //Define a rotation Holder PropertyValuesHolder rotationHolder= PropertyValuesHolder.ofFloat( "rotation", 60f,40f,100f,-60f,40f,88f,77f); //Define a transparent Holder PropertyValuesHolder alphaHolder= PropertyValuesHolder.ofFloat( "alpha", 0.01f,0.5f,1.0f,0.8f,0.2f,0.0f); //Load into ObjectAnimator ObjectAnimator objectAnimator=ObjectAnimator.ofPropertyValuesHolder(ballImageView,rotationHolder,alphaHolder); objectAnimator.setDuration(3000); objectAnimator.start(); }

2. Methods and parameters

You can see the parameters of this method:

ObjectAnimator ofPropertyValuesHolder(Object target,PropertyValuesHolder... values)
PropertyValuesHolder ofFloat(String propertyName, float... values)

Object target is the control to display the animation

PropertyValuesHolder... values loads multiple propertyvaluesholders

String propertyName represents the parameter to be reflected, which is the same as that of ObjectAnimation

float... values are variable length parameters
This method also has the following pictures:

The ofObject() method is similar to ObjectAnimation, and also needs to customize the TypeEvaluator.

2, Keyframe

1. Understanding and use

Look at the name, is to understand the meaning of key frame. In the animation, do some operations in a certain frame, so as to achieve a more obvious effect of contrast effect.
Keyframes represent where an object should be at which point in time.
Specific use:

public void doPropertyValuesHolderKeyFrame(){ //First keyframe1, starting from schedule 0.6, when the schedule is 60%, the value is 0.1f Keyframe keyframe1=Keyframe.ofFloat(0.6f,0.1f); //Middle keyframe2 Keyframe keyframe2=Keyframe.ofFloat(0.1f,0.8f); //Tail keyframe3, ending with 50% progress, the value is 0.2f at this time Keyframe keyframe3=Keyframe.ofFloat(0.5f,0.2f); //Load into the Holder and set the method to reflect. This is reflected by setAlpha() method, which controls transparency PropertyValuesHolder alphaHolder=PropertyValuesHolder.ofKeyframe("alpha",keyframe1,keyframe2,keyframe3); //Load into Holder to ObjectAnimator or ValueAnimation ObjectAnimator objectAnimator=ObjectAnimator.ofPropertyValuesHolder(ballImageView,alphaHolder); objectAnimator.setDuration(3000); objectAnimator.start(); }

2. Methods and parameters

Keyframe ofFloat(float fraction, float value)

float fraction represents progress

float value indicates the value under this progress

PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values)

String propertyName set method to reflect

Keyframe... values in keyframe

Keyframe's method is similar to other methods.

Keyframe set method, set progress, interpolator, numerical value.
When no interpolator is set, the default is linear interpolator

keyframe1.setInterpolator(new LinearInterpolator()); //Default linear interpolator

3. Frame operation

Write a conclusion directly:

  • If frame 0 is removed, the first key is taken as the starting position
  • If the end frame is removed (progress is 1), the end position is the last keyframe
  • Using keyframe to build an animation requires at least 2 frames
3, ViewPropertyAnimator

1. Understanding and use

The animation can be defined quickly and some definitions can be omitted in the form of serial. When drawing the interface, the animation can be started, which saves more consumption than others.
For example:

ballImageView.animate().alpha(0.5f).rotation(360f).scaleX(1.5f).translationX(100f);

2. Parameters and methods

You can see the return values of these methods, which are basically ViewPropertyAnimator


Refer to another table:

function Meaning alpha(float value) Set transparency scaleY(float value) Set the scale size in Y direction scaleX(float value) Set the scale size in the X-axis direction translationY(float value) Set movement value in Y direction translationX(float value) Set movement value in X direction rotation(float value) Set the degree of rotation around the Z axis rotationX(float value) Set the degree of rotation around the x-axis rotationY(float value) Set the degree of rotation around the Y axis x(float value) The final position of the upper left corner relative to the parent container in the X-axis direction y(float value) The final position of the upper left corner coordinate relative to the parent container in the Y-axis direction alphaBy(float value) Set transparency increment rotationBy(float value) Set rotation increment around Z axis rotationXBy(float value) Set rotation increment around X oil rotationYBy(float value) Set the increment of Y-axis rotation translationXBy(float value) Set the increment of movement value in X direction translationYBy(float value) Set the increment of movement value in Y direction scaleXBy(float value) Set the scale size increment in the X direction scaleYBy(float value) Set scale size increment in Y direction xBy(float value) The position increment of the upper left corner coordinate relative to the parent container in the X-axis direction yBy(float value) Position increment in Y direction relative to the upper left corner of the parent container setlnterpolator(Timelnterpolator interpolator) Set interpolator setStartDelay(long startDelay) Set start delay setDuration(long duration) Animation duration 4, animateLayoutChanges

android:animateLayoutChanges="true"
Add animation when Layout adds controls or removes controls, but only the default animation can be used.

<LinearLayout android:animateLayoutChanges="true" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"/>
5, LayoutTransition

LayoutTransition can control the animation of ViewGroup, and can use customized animation.
Specific use:

public void doLayoutTransition(){ LinearLayout linearLayout=new LinearLayout(this); //1. Create an instance LayoutTransition transition=new LayoutTransition(); //2. Create animation ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(null,"rotation",0f,90f,0f); //3. Set the form of animation transition.setAnimator(LayoutTransition.DISAPPEARING,objectAnimator); //4. Set LayoutTransition to ViewGroup linearLayout.setLayoutTransition(transition); //5. Open source animation library NineOldAndroids }

setAnimator(int transitionType, Animator animator)

In this method, the transitionType has five options

Change ABCD animating animation applied by other elements that need to change because a new element is to be displayed in the container

_Change ﹣ separating ﹣ when an element in a container is going to disappear, the animation applied by other elements that need to change (many problems, not commonly used)

_CHANGING? Animation changes for the element being changed in the container

_Animation defined when the applying UU element appears in the container

_Animation defined when the separating UU element disappears in the container

6, PathMeasure

PathMeasure is similar to a calculator, which can calculate the coordinates and length of the target path

1. Initialization

public void doPathMeasure(){ Path path=new Path(); //Initialization method 1 PathMeasure pathMeasure1=new PathMeasure(); pathMeasure1.setPath(path,true); //Initialization method 2 PathMeasure pathMeasure2=new PathMeasure(path,false); }

setPath(Path path, boolean forceClosed)
Path is the target path to be calculated.
If forceClosed is closed, true will calculate the Path in the closed state, and false will calculate according to the original situation of Path.

2. Function call

Customize a view

public class PathView extends View { Path mPath; Paint mPaint; PathMeasure mPathMeasure; public PathView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); mPath=new Path(); mPaint=new Paint(); mPathMeasure=new PathMeasure(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.translate(250,250); //Canvas move mPaint.setColor(Color.BLUE); //stroke color mPaint.setStrokeWidth(5); //Brush thickness mPaint.setStyle(Paint.Style.STROKE); //Brush style mPath.moveTo(0,0); mPath.lineTo(0,100); mPath.lineTo(100,100); mPath.lineTo(100,0); mPathMeasure.setPath(mPath,true); Log.v("showLog", "getLength()=="+mPathMeasure.getLength() +" isClosed()=="+ mPathMeasure.isClosed()); //Result 400.0 true mPathMeasure.setPath(mPath,false); Log.v("showLog", "getLength()=="+mPathMeasure.getLength() +" isClosed()=="+ mPathMeasure.isClosed()); //Result 300.0 false canvas.drawPath(mPath,mPaint); //Draw path } }

Painting effect:

2.1 PathMeasure.getLength()

The PathMeasure.getLength() function measures the length of the path

2.2 PathMeasure.isClosed()

The PathMeasure.isClosed() function returns whether to measure the closed state

2.3 PathMeasure.nextContour()

mPath.addRect(-50, -50, 50, 50, Path.Direction.CW); canvas.drawPath(mPath, mPaint); mPath.addRect(-100, -100, 100, 100, Path.Direction.CW); canvas.drawPath(mPath, mPaint); mPath.addRect(-120, -120, 120, 120, Path.Direction.CW); canvas.drawPath(mPath, mPaint); mPathMeasure.setPath(mPath, false); do { float len = mPathMeasure.getLength(); Log.v("showLog", "len=" + len); } while (mPathMeasure.nextContour());

effect:

Print results:

len=400.0 len=800.0 len=960.0

PathMeasure.nextContour() gets in the same order as the Path you added

PathMeasure.getLength() just gets the length of the current path, not the whole length

2.3 getSegment()

Using the getSegment function requires disabling hardware acceleration to add to the constructor
setLayerType(LAYER_TYPE_SOFTWARE,null);

mPath.addRect(-50, -50, 50, 50, Path.Direction.CW); mPathMeasure.setPath(mPath,false); //Calculated path mPathMeasure.getSegment(0,150,mDstPath,true); //Intercept and add to mDstPath, add, not others canvas.drawPath(mPath, mPaint); //Draw the original path canvas.translate(200,0); //Canvas move mPaint.setColor(Color.RED); canvas.drawPath(mDstPath, mPaint); //Draw the added mDstPath
boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)

The starting point of the interception of startD path is the point in the upper left corner

stopD intercept stop point

path added after dst interception

startWithMoveTo whether to save as is, true to save as is, false to connect the initial point and the end point, not necessarily the same shape as the original
The effect of the above code: the direction of the screenshot is related to the generation direction of the original path

2.4 example of dynamic circle drawing

code:

public class PathView extends View { Path mPath, mDstPath; Paint mPaint; PathMeasure mPathMeasure; float mCurAnimValue; public PathView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); setLayerType(LAYER_TYPE_SOFTWARE, null); mPath = new Path(); mDstPath = new Path(); mPaint = new Paint(); mPathMeasure = new PathMeasure(); mPaint.setColor(Color.BLUE); //stroke color mPaint.setStrokeWidth(5); //Brush thickness mPaint.setStyle(Paint.Style.STROKE); //Brush style mPath.addCircle(100, 100, 50, Path.Direction.CW); //A complete circle mPathMeasure.setPath(mPath, true); //path to calculate ValueAnimator animator = ValueAnimator.ofFloat(0, 1); //Progress 0 ~ 1 animator.setRepeatCount(ValueAnimator.INFINITE); //Infinite cycle animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mCurAnimValue = (Float) animation.getAnimatedValue(); //Get current progress invalidate();//Redraw, execute onDraw() method again } }); animator.setDuration(5000); animator.start(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.translate(100, 100); //Canvas move float stop=mPathMeasure.getLength()*mCurAnimValue; //A progress determines a intercept point mDstPath.reset(); mPathMeasure.getSegment(0,stop,mDstPath,true); //Add a little bit canvas.drawPath(mDstPath,mPaint); //Every time there is a progress update, draw a small segment to intercept } }

effect:

2.5 getPosTan()

Let's first look at the definition of the function:

boolean getPosTan(float distance, float pos[], float tan[])

float distance the actual length of the path

float pos [] coordinate value of the point. X and y pos[0]=x, pos[1]=y

float tan [] tangent value of the point. X and y pos[0]=x, pos[1]=y Tan < a = Y / X

2.6 example of arrow drawing circle

code:

public class PathView extends View { Path mPath, mDstPath; Paint mPaint; PathMeasure mPathMeasure; float mCurAnimValue; Bitmap mArrowBmp; float[] mPos; float[] mTan; int mCenterX,mCenterY; float mRadius; public PathView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); setLayerType(LAYER_TYPE_SOFTWARE, null); mPath = new Path(); mDstPath = new Path(); mPaint = new Paint(); mPathMeasure = new PathMeasure(); mPos=new float[2]; mTan=new float[2]; //Load arrow picture mArrowBmp= BitmapFactory.decodeResource(getResources(), R.drawable.arrow); mPaint.setColor(Color.BLUE); //stroke color mPaint.setStrokeWidth(5); //Brush thickness mPaint.setStyle(Paint.Style.STROKE); //Brush style mPath.addCircle(540, 972, 486, Path.Direction.CW); //A complete circle mPathMeasure.setPath(mPath, true); //path to calculate ValueAnimator animator = ValueAnimator.ofFloat(0, 1); //Progress 0 ~ 1 animator.setRepeatCount(ValueAnimator.INFINITE); //Infinite cycle animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mCurAnimValue = (Float) animation.getAnimatedValue(); //Get current progress invalidate();//Redraw, execute onDraw() method again } }); animator.setDuration(5000); animator.start(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { /* * The minimum value of h,w is obtained; * >> 1 The shift is the same as / 2; * Multiply by 0.9f to represent 90% of the layout * */ mRadius = (Math.min(h, w) >> 1) * 0.9f; // Central coordinate mCenterX = w / 2; mCenterY = h / 2; Log.v("showLog",mCenterX+" "+mCenterY+" "+mRadius); postInvalidate(); super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); float stop=mPathMeasure.getLength()*mCurAnimValue; //A progress determines a intercept point mDstPath.reset(); mPathMeasure.getSegment(0,stop,mDstPath,true); //Add a little bit canvas.drawPath(mDstPath,mPaint); //Every time there is a progress update, draw a small segment to intercept mPathMeasure.getPosTan(stop,mPos,mTan); //Obtain tangent value and coordinates of each point /** * Math.atan2(mTan[1],mTan[0])Get the radian value of tan * *180.0/Math.PI Convert to angle value * */ float degrees=(float)(Math.atan2(mTan[1],mTan[0])*180.0/Math.PI); Matrix matrix=new Matrix(); /** * Rotate the picture around the center point by a specified angle * postRotate(float degrees, float px, float py) * degrees Is the angle (px,py) is the center of the picture * */ matrix.postRotate(degrees,mArrowBmp.getWidth()/2,mArrowBmp.getHeight()/2); /** * Move the picture from the default (0, 0) point to the front of the path * */ matrix.postTranslate(mPos[0]-mArrowBmp.getWidth()/2,mPos[1]-mArrowBmp.getHeight()/2); //Draw pictures canvas.drawBitmap(mArrowBmp,matrix,mPaint); } }

effect:

2.7 getMatrix()

Parameter type:

boolean getMatrix(float distance, Matrix matrix, int flags)

usage method:

//Calculate azimuth Matrix matrix = new Matrix(); //Get location information mPathMeasure.getMatrix(stop,matrix,PathMeasure.POSITION_MATRIX_FLAG); //Get trimming information mPathMeasure.getMatrix(stop,matrix,PathMeasure.TANGENT_MATRIX_FLAG);

2.8 payment success examples

public class TickView extends View { Path mPath, mDstPath; Paint mPaint; PathMeasure mPathMeasure; float mCurAnimValue; int mCenterX, mCenterY; float mRadius; public TickView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); setLayerType(LAYER_TYPE_SOFTWARE, null); mPath = new Path(); mDstPath = new Path(); mPaint = new Paint(); mPathMeasure = new PathMeasure(); mPaint.setColor(Color.BLUE); //stroke color mPaint.setStrokeWidth(5); //Brush thickness mPaint.setStyle(Paint.Style.STROKE); //Brush style mCenterX = 540; mCenterY = 972; mRadius = 486 / 2; /** * circular * */ mPath.addCircle(mCenterX, mCenterY, mRadius, Path.Direction.CW); /** * Check mark * */ mPath.moveTo(mCenterX - mRadius / 2, mCenterY); mPath.lineTo(mCenterX, mCenterY + mRadius / 2); mPath.lineTo(mCenterX + mRadius / 2, mCenterY - mRadius / 3); mPathMeasure.setPath(mPath, false); //path to calculate ValueAnimator animator = ValueAnimator.ofFloat(0, 2); //Progress 0-1 is circle, 1-2 is checkmark animator.setRepeatCount(ValueAnimator.RESTART); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mCurAnimValue = (Float) animation.getAnimatedValue(); //Get current progress invalidate();//Redraw, execute onDraw() method again } }); animator.setDuration(5000); animator.start(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { /* * The minimum value of h,w is obtained; * >> 1 The shift is the same as / 2; * Multiply by 0.9f to represent 90% of the layout * */ mRadius = (Math.min(h, w) >> 1) * 0.9f; // Central coordinate mCenterX = w / 2; mCenterY = h / 2; Log.v("showLog", mCenterX + " " + mCenterY + " " + mRadius); postInvalidate(); super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mCurAnimValue < 1) { float stop = mPathMeasure.getLength() * mCurAnimValue; mPathMeasure.getSegment(0, stop, mDstPath, true); } else if (mCurAnimValue == 1) { mPathMeasure.getSegment(0, mPathMeasure.getLength(), mDstPath, true); mPathMeasure.nextContour(); } else { float stop = mPathMeasure.getLength() * (mCurAnimValue - 1); mPathMeasure.getSegment(0, stop, mDstPath, true); } canvas.drawPath(mDstPath, mPaint); } }

effect:

How many setbacks will we encounter in programming? Table give up, the end of the desert must be oasis.

7 May 2020, 05:47 | Views: 3866

Add new comment

For adding a comment, please log in
or create account

0 comments