This article has participated in the activity of “New person creation Ceremony”, and started the road of digging gold creation together.

The previous article “View system (six) View workflow entrance” mentioned that the View workflow includes measure, layout and draw process, today we will look at the View draw process is what.

Note: the source code is based onAndroid 12)

View draw process is very simple, the source note official also write very clear, we look at View draw method:

    public void draw(Canvas canvas) {...// Step 1, draw the background, if neededdrawBackground(canvas); .// skip step 2 & 5 if possible (common case).// Step 2, save the canvas' layers.// Step 3, draw the contentonDraw(canvas); .// Step 4, draw the childrendispatchDraw(canvas); .// Step 5, draw the fade effect and restore layers.// Step 6, draw decorations (foreground, scrollbars)onDrawForeground(canvas); .// Step 7, draw the default focus highlight
        drawDefaultFocusHighlight(canvas);
Copy the code

The overview

The official notes clearly state every step of the way:

  1. If necessary, draw the background (drawBackground)
  2. Save the current Canvas layer
  3. Draw the contents of the View (onDraw)
  4. Draw child View (dispatchDraw)
  5. If desired, draw the faded edges of the View, similar to a shadow effect
  6. Draw decorations, such as scroll bars (onDrawForeground)
  7. Draw default focus highlighting (drawDefaultFocusHighlight)

It is stated in the comments that steps 2 and 5 can be skipped, which will not be explained here, but will focus on the other steps.

Step 1: Draw the background

Enter the View’s drawBackground method:

    private void drawBackground(Canvas canvas) {
        finalDrawable background = mBackground; . setBackgroundBounds();/ / 1. background.draw(canvas);/ / 2
Copy the code

The background range is set in comment 1, and the background is drawn in Comment 2 using the draw method of Drawable, which will be explained in more detail in a later article. Note 1 setBackgroundBounds sets the background range:

    void setBackgroundBounds(a) {
        if(mBackgroundSizeChanged && mBackground ! =null) {
            mBackground.setBounds(0.0, mRight - mLeft, mBottom - mTop);    / / 1
            mBackgroundSizeChanged = false; rebuildOutline(); }}Copy the code

Note 1 calls the mbackground-setbounds method with mRight, mLeft, mBottom, and mTop arguments to the View to set the bounds.

Step 2: Save the current Canvas layer

Step 3: Draw the contents of the View

Step 3 called the View onDraw method, this method is an empty implementation, because different views have different content, so we need to achieve our own, that is, in the custom View rewrite the method to achieve our own draw.

    protected void onDraw(Canvas canvas) {}Copy the code

Step 4: Draw the child View

Step 4 calls the dispatchDraw method, which is also an empty implementation:

    protected void dispatchDraw(Canvas canvas) {}Copy the code

ViewGroup overrides this method. Let’s look at the dispatchDraw method of ViewGroup:

    protected void dispatchDraw(Canvas canvas) {...for (int i = 0; i < childrenCount; i++) {
            ...
            more |= drawChild(canvas, transientChild, drawingTime);
Copy the code

The dispatchDraw method traverses the child View and calls the drawChild method. Let’s continue with the drawChild method:

    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        return child.draw(canvas, this, drawingTime);
    }
Copy the code

The drawChild method actually calls the child View’s draw method to draw the child View

Step 5: Draw the shadow effect of the View

Step 6: Paint decorations

Step 6 Call onDrawForeground method:

    public void onDrawForeground(Canvas canvas) {
        onDrawScrollIndicators(canvas);
        onDrawScrollBars(canvas);

        finalDrawable foreground = mForegroundInfo ! =null ? mForegroundInfo.mDrawable : null;
        if(foreground ! =null) {
            if (mForegroundInfo.mBoundsChanged) {
                mForegroundInfo.mBoundsChanged = false;
                final Rect selfBounds = mForegroundInfo.mSelfBounds;
                final Rect overlayBounds = mForegroundInfo.mOverlayBounds;

                if (mForegroundInfo.mInsidePadding) {
                    selfBounds.set(0.0, getWidth(), getHeight());
                } else {
                    selfBounds.set(getPaddingLeft(), getPaddingTop(),
                            getWidth() - getPaddingRight(), getHeight() - getPaddingBottom());
                }

                final intld = getLayoutDirection(); Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); foreground.setBounds(overlayBounds); } foreground.draw(canvas); }}Copy the code

This is mainly about drawing the ScrollBar and other decorations.

Step 7: Draw the default focus highlighting effect

    private void drawDefaultFocusHighlight(Canvas canvas) {
        if(mDefaultFocusHighlight ! =null && isFocused()) {
            if (mDefaultFocusHighlightSizeChanged) {
                mDefaultFocusHighlightSizeChanged = false;
                final int l = mScrollX;
                final int r = l + mRight - mLeft;
                final int t = mScrollY;
                final intb = t + mBottom - mTop; mDefaultFocusHighlight.setBounds(l, t, r, b); } mDefaultFocusHighlight.draw(canvas); }}Copy the code

To learn more, please check out my personal blog:droidYu