English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
This article introduces an Android imitation iQIYI loading animation example, the specific code is as follows:
Effect diagram:
Knowledge points used:
If you are not familiar with Path and ValueAnimator, it is recommended to read these big神的 Blogs: the most suitable articles for me on Custom View, Detailed Tutorial and Practice on Custom View, this is also a tutorial and practice, thank them for their efforts! (I hope everyone can read it carefully and get a lot of inspiration).
Animation disassembly
The difficulty here lies mainly in the calculation of coordinates, and I will explain it in detail next:
I believe this picture has been taken out, combined with the sine and cosine functions, p1,p2,p3the coordinates are also determined.
p1.x = -(int) ((radius / 2 * Math.tan(30 * Math.PI / 180)));
p1.y = -radius / 2;
p2.x = p1.x;
p2.y = radius / 2;
p3.x = (int) (radius / 2 / Math.sin(60 * Math.PI / 180));
p3.y = 0;
define some properties
private static final String DEFAULT_COLOR = "#00ba9b"; private static final int DEFAULT_SIZE = 50; //default size private static final int DRAW_CIRCLE = 10001; //Status marker to draw the circle and triangle and execute the animation of drawing the circle private static final int ROTATE_TRIANGLE = 10002; //Status marker to execute the animation of rotating the triangle and retracting the circle private Context mContext; private Paint trianglePaint; //The pen of the triangle private Paint circlePaint; //The circle pen private float paintStrokeWidth = 1; // Set the width of the circle private long duration = 800; //Execution time private int mWidth; //The width and height of the View private int mHeight; private Path trianglePath; //The path of the triangle private Path circlePath; //The path of the circle private Path dst; //The path calculated by pathMeasure private Point p1, p2, p3; //The three points of the triangle private ValueAnimator animator; //Property animation is mainly to get 0-1to execute the animation private float mAnimatorValue = 0; //Store the obtained 0-1value private int mCurrentState = 0; //The current state private int radius = 0; //The radius of the circle private float startSegment; //The length of the circle drawn at the beginning private PathMeasure mMeasure; //Measure the path private int triangleColor = -1; private int circleColor = -1;
Set the path
1Since the triangle always exists, let's draw a triangle first using the path, as we already know the coordinates of the three vertices of the triangle, drawing the triangle becomes very easy.
trianglePath = new Path(); p1 = new Point(); p2 = new Point(); p3 = new Point(); trianglePath.moveTo(p1.x, p1.y); trianglePath.lineTo(p2.x, p2.y); trianglePath.lineTo(p3.x, p3.y); trianglePath.close();
So the triangle's path is set up, and we can draw the triangle onto the canvas by calling canvans.drawPath().
2. Then it's time to draw the circle, as mentioned before, the circle has a gap, so we also add the circle to the path here. The reason we didn't draw it directly on the canvas is because we still need to calculate the circumference of the circle later, and these operations can be handled by the path.
circlePath = new Path(); RectF circleRect = new RectF(-radius, -radius, radius, radius); circlePath.addArc(circleRect, 268, 358); // This is from the circle268° to start drawing, draw258° to leave a gap of two degrees
Set property animation
Since the animation needs a set of 0-1data
Here we use the numerical values provided by property animation to implement the animation.
private void initAnimation() { TimeInterpolator timeInterpolator = new AccelerateDecelerateInterpolator(); animator = ValueAnimator.ofFloat(0, 1).setDuration(duration); animator.setInterpolator(timeInterpolator); animator.setRepeatMode(ValueAnimator.RESTART); animator.setRepeatCount(ValueAnimator.INFINITE); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mAnimatorValue = (float) animation.getAnimatedValue(); //Here we will get a 0-1value invalidate(); // Here we perform the redrawing } }); animator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) {}} } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { //Here, the state transition is performed, and different animations are executed switch (mCurrentState) { case DRAW_CIRCLE: mCurrentState = ROTATE_TRIANGLE; break; case ROTATE_TRIANGLE: mCurrentState = DRAW_CIRCLE; break; default: break; } } }); }
onDraw
Analyze the onDraw method
protected void onDraw(Canvas canvas) { super.onDraw(canvas); //Move the origin to the center position canvas.translate(mWidth / 2, mHeight / 2); // Reset path dst dst.reset(); //Determine the current state switch (mCurrentState) { //This is the first state we mentioned case DRAW_CIRCLE: //This line is to get the starting position of the path to be cut (dst), and by observing the animation carefully, we can see that the start of the circle is from a position to //draw at both ends, this position is about the circle's1/5, when drawing to the starting point of the circle, start drawing from the starting point of the circle, I execute this animation //The time is roughly set to 0-1 0.3position left and right. startSegment = (float) (mMeasure.getLength() / 5 * ((0.3 - mAnimatorValue) > 0 ? (0.3 - mAnimatorValue) : 0)); //There is nothing here, just draw a triangle trianglePaint.setStyle(Paint.Style.FILL_AND_STROKE); canvas.drawPath(trianglePath, trianglePaint); //This method is to get the segment you want to cut, the first parameter is the starting position, the second parameter is the ending position, the third parameter is //The number is the truncated path, added to the path (dst), note that it is added, not replaced, so it needs to be reset in advance, the fourth parameter is //Do you want to move the starting point to the starting point of the current path to keep the path in dst unchanged (for example, if there was a path in dst before, here //Set to false to ensure the continuity of dst, and then move the starting point of the path added after moving dst to the end of the previous path to maintain continuity. mMeasure.getSegment(startSegment, mMeasure.getLength()) * mAnimatorValue, dst, true); canvas.drawPath(dst, circlePaint); break; //Second animation case ROTATE_TRIANGLE: //Save the canvas because two animations need to be executed, save the initial state of the canvas canvas.save(); //Then first execute the rotation of the triangle trianglePaint.setStyle(Paint.Style.FILL_AND_STROKE); canvas.rotate(360 * mAnimatorValue); canvas.drawPath(trianglePath, trianglePaint); //Restore the canvas canvas.restore(); //Then comes the disappearance of the outer circle, which is actually the same as drawing a circle. Here we have a set of 0-1of the changing value, we just need //When slicing a segment, let the starting point approach the total length continuously, and a disappearing effect will appear. mMeasure.getSegment(mMeasure.getLength(), * mAnimatorValue, mMeasure.getLength(), dst, true); canvas.drawPath(dst, circlePaint); break; default: break; } }
That's all for this article. I hope it will be helpful to everyone's learning and that everyone will support the Yelling Tutorial more.
Declaration: The content of this article is from the Internet, and the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, has not been manually edited, and does not assume any relevant legal liability. If you find any content suspected of copyright infringement, please send an email to: notice#w3Please report via email to codebox.com (replace # with @ when sending an email) and provide relevant evidence. Once verified, this site will immediately delete the infringing content.