draw process of View
View's three main processes, measure,layout,draw, start at the top from ViewRootImpl. Specifically, from performance Traversals.
Drawing the View tree is initiated by the performance Traversals () method of the ViewRoot object calling the draw() method. It is noteworthy that every time a drawing is initiated, the views of each View tree will not be redrawn, but only those views that "need to be redrawn" will be redrawn. The internal variables of the View class contain a flag bit DRAWN, which will be added to the View when it needs redrawing. .
ViewRootImpl.java
- private void performTraversals() {
- Get Surface objects for graphics rendering
- ....
- performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
- .........
- performLayout(lp, desiredWindowWidth, desiredWindowHeight);
- ........
- performDraw();
- ..........
- }
PerfmTraversals calls performDraw (), and performDraw () What we need to pay attention to for the time being is that it calls draw (full Redraw Needed).
private void draw(boolean fullRedrawNeeded) {
Surface surface = mSurface; //The surface we have worked so hard to obtain
........
if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
return;
}
.......
}
DraSoftware is called at draw().
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int yoff,
boolean scalingRequired, Rect dirty) {
.......
canvas = mSurface.lockCanvas(dirty); //Obtain and Lock Canvas Drawing Objects through Surface Objects
.......
mView.draw(canvas); //Drawing from DecorView, which is the root view of the whole Window s, will result in drawing the whole tree.
.......
surface.unlockCanvasAndPost(canvas); //Release the Canvas lock and notify Surface Flinger to update the area
.......
}
DraSoftware () calls mView.draw(canvas), and it's only here that you really start drawing with a brush.
View.java
public void draw(Canvas canvas) {
final int privateFlags = mPrivateFlags;
final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
/*
* Draw traversal performs several drawing steps which must be executed
* in the appropriate order:
*
* 1. Draw the background
* 2. If necessary, save the canvas' layers to prepare for fading
* 3. Draw view's content
* 4. Draw children
* 5. If necessary, draw the fading edges and restore layers
* 6. Draw decorations (scrollbars for instance)
*/
// Step 1, draw the background, if needed
int saveCount;
if (!dirtyOpaque) {
drawBackground(canvas);//Drawing background
}
// skip step 2 & 5 if possible (common case)
final int viewFlags = mViewFlags;
boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
if (!verticalEdges && !horizontalEdges) {//The fading Edge property is not set, and the gradient projection effect is not set.
// Step 3, draw the content
if (!dirtyOpaque) {
onDraw(canvas);
}
// Step 4, draw the children
dispatchDraw(canvas);
// Step 6, draw decorations (scrollbars)
onDrawScrollBars(canvas);
if (mOverlay != null && !mOverlay.isEmpty()) {
mOverlay.getOverlayView().dispatchDraw(canvas);
}
// we're done...
return;
}
...//Processing settings for gradient projection effects
}
The view.draw() method above is divided into six steps:
Drawing Background
2. Preparing for the fifth step of drawing fadin projection gradient effect
3. Drawing id=content, that is DecorView.(onDraw(canvas);), you can understand the drawing view itself.
4. Draw child view (dispatch Draw (canvas);
5. Drawing fadin projection gradient effect
6. Draw sliders, (onDrawScrollBars(canvas);)
Among them, the common processes are only 1-3-4-6.
The onDraw() in step 3 above is not in View
The implementation is just an empty method. ViewGroup does not override this method either. Because each view is different, it needs to be drawn independently.
The dispatchDraw in Step 4 is not in View
The implementation is just an empty method. ViewGroup overrides this method. This method is used to traverse the draw() method that calls dispatchDraw() to transfer child, so that draw events are passed on layer by layer.
Now let's look at the general process of ViewGroup. ViewGroup does not rewrite the draw() method of View. Instead, it rewrites dispatchDraw(). In fact, this method of ViewGroup is used to draw child view as mentioned in View. Actually, viewing dispatchDraw() will also find that it calls child draw() by transferring drawChild().
In fact, looking at the source code of LinearLayout shows that although it implements the onDraw method, at least it draws a Divider, that is, whether there is a headline between each child view, and whether there is a line between the beginning and the end.
protected void onDraw(Canvas canvas) {
if (mDivider == null) {
return;
}
if (mOrientation == VERTICAL) {
drawDividersVertical(canvas);
} else {
drawDividersHorizontal(canvas);
}
}
void drawDividersVertical(Canvas canvas) {
final int count = getVirtualChildCount();
for (int i = 0; i < count; i++) {
final View child = getVirtualChildAt(i);
if (child != null && child.getVisibility() != GONE) {
if (hasDividerBeforeChildAt(i)) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int top = child.getTop() - lp.topMargin - mDividerHeight;
drawHorizontalDivider(canvas, top);
}
}
}
if (hasDividerBeforeChildAt(count)) {
final View child = getVirtualChildAt(count - 1);
int bottom = 0;
if (child == null) {
bottom = getHeight() - getPaddingBottom() - mDividerHeight;
} else {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
bottom = child.getBottom() + lp.bottomMargin;
}
drawHorizontalDivider(canvas, bottom);
}
}
It is important to note that the padding parameters of the view itself are used in draw ing.
But the margin parameter is not used in the view's own draw s, but is already controlled in its parent. (The margin parameter can be viewed in LayoutParams.)
Reference resources:
View Display Process 1-View draw Preparations
draw process analysis in Android (combined with the latest Android 4.0.4 source code)