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 on
Android 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:
- If necessary, draw the background (
drawBackground
) - Save the current Canvas layer
- Draw the contents of the View (
onDraw
) - Draw child View (
dispatchDraw
) - If desired, draw the faded edges of the View, similar to a shadow effect
- Draw decorations, such as scroll bars (
onDrawForeground
) - 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