English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Android Imitates Iqiyi Loading Animation Example

This article introduces an Android imitation iQIYI loading animation example, the specific code is as follows:

Effect diagram:

Knowledge points used:

  1. Path
  2. ValueAnimator

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

  1. A circle is first drawn out slowly in a clockwise direction (the circle is not a closed circle)
  2. This step is a combination animation, where the circle slowly disappears while the triangle rotates counterclockwise

The difficulty here lies mainly in the calculation of coordinates, and I will explain it in detail next:

  1. Here, we take the center as the origin of the x, y axes, with the downward direction as the positive direction of the x-axis, and the rightward direction as the positive direction of the y-axis. If the view size is equal width and height, at this time, the radius of the circle can be set to half of the width or height. If it is not equal width and height, the minimum value of the width or height should be taken as half, as the radius of the circle.
  2. Next is the triangle, which is also a difficult point to determine the coordinates. This triangle is an equilateral triangle, and we hope that the triangle rotates around the center of the circle. Therefore, the distance from the center of the circle to each vertex of the triangle is equal. Here, I set the side length of the triangle to be half of the radius of the circle.

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.

You May Also Like