This article belongs to the Android technology discussion article, reading about five minutes

Original article, reproduced please indicate the source.

If you don’t have time, you can skip the article and click the project address. If you like, you can give it a star.

Without saying a word, the effect is served!

Knowledge sequence:

  • Canvas to draw
  • TextPaint
  • Path
  • PathMeasure [measure Path]

The code analysis

Gets the outline Path of the text

In TextPaint there is such a method, getTextPath, as follows:

public void getTextPath(String text, int start, int end,
                            float x, float y, Path path) {
        if ((start | end | (end - start) | (text.length() - end)) < 0) {
            throw new IndexOutOfBoundsException();
        }
        nGetTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, start, end, x, y,
                path.mutateNI());
    }
Copy the code

👀 where nGetTextPath is called a native function, the specific implementation need not care. You just need to know the parameters of the function.

  • Parameter Meanings:
    • Text: indicates the text content
    • Start: The subscript of the first character in the text to be measured
    • End: Adds 1 to the subscript of the last character of the text to be measured
    • X: indicates the coordinate x of the starting point of Path
    • Y: Indicates the coordinate y of the starting point of the Path
    • Path: indicates the path of the final measurement

Path piecewise drawing

The PathMeasure class can be said to be a path-related tool parsing class, which is mostly native functions, so there is no need to go into the implementation details. You just need to know how to use it. In the first step, after we get the outline Path of the text, this step will draw the Path by section. In the code, the detailed process of drawing is implemented by the CanvasView class. Look at the code and set the text outline Path in:

// Keep a copy of the original Path to draw the final color text mOrignalPath = orignalPath; if (null == mPathMeasure) { mPathMeasure = new PathMeasure(); } // Reset the path manimpath.reset (); mAnimPath.moveTo(0, 0); mPathMeasure.setPath(orignalPath, false); // getLength () gets the length of the current path; While nextContour () method is to switch Path to the next section of Path, which is mostly used in complex Path mTextCount = 0; Path while (mpathmeasure.nextcontour ()) {mTextCount++; } // PathMeasure resets mPathMeasurement. setPath(orignalPath, false); mPaint.setStyle(Paint.Style.STROKE);Copy the code
  • Where the member variable mAnimPath is used inonDraw()The Path used to draw within the method. We’ll keep passingPathMeasureRefresh this Path for animation to run smoothly.

Next comes the engine code, which uses the property animation. See the code implementation:

If (null == mValueAnimator) {// If a text Path contains n small paths, then the property animation will Repeat n times, MValueAnimator = ValueAnimator.offloat (0.0f, 1.0f); mValueAnimator = ValueAnimator.offloat (0.0f, 1.0f); mValueAnimator.setDuration(900); mValueAnimator.setInterpolator(new LinearInterpolator()); } / / engine infinitely repeated mValueAnimator. SetRepeatCount (ValueAnimator. INFINITE); mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = (float) animation.getAnimatedValue(); GetSegment (0, mPathMeasure.getLength() * value, mAnimPath, true); // Assign a small Path from 0% to 100% to mAnimPath. invalidate(); }}); mValueAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationRepeat(Animator animation) {  super.onAnimationRepeat(animation); // After drawing a Path, draw the next Path until it is complete. if (! mPathMeasure.nextContour()) { animation.end(); } invalidate(); }});Copy the code
  • The specific reasons are stated in the notes. This engine setup, in which every bit of Path takes the same amount of time regardless of its length, makes the animation look slower and faster.
  • It’s easy to keep the animation running at a constant speed by measuring the original Path in advance, setting a total time, and then proportionally dividing the time according to the length of the small Path. This allows the animation to proceed at a constant speed. Specific code no longer more words 😘, interested partners can try.

Let’s look at the implementation of the onDraw() method in CanvasView:

@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (null ! = mPathMeasure && mPathMeasure.getLength() == 0) { mPaint.setStyle(Paint.Style.FILL); canvas.drawPath(mOrignalPath, mPaint); return; } canvas.drawPath(mAnimPath, mPaint); }Copy the code
  • Here the code is simpler, just keep drawing mAnimPath until the Path is drawn. After the Path is drawn, set the painting style of the brush and fill in the margins of the text.

The above. Is the main idea of this project analysis. Don’t miss it if you pass by. Add oneStarBai 😄.