draw process of View and ViewGroup

Keywords: Java Android

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
  1. private void performTraversals() {
  2. Get Surface objects for graphics rendering
  3. ....
  4. performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
  5. .........
  6. performLayout(lp, desiredWindowWidth, desiredWindowHeight);
  7. ........
  8. performDraw();
  9. ..........
  10. }
PerfmTraversals calls performDraw (), and performDraw () What we need to pay attention to for the time being is that it calls draw (full Redraw Needed).
  1. private void draw(boolean fullRedrawNeeded) {
  2. Surface surface = mSurface; //The surface we have worked so hard to obtain
  3. ........
  4. if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
  5. return;
  6. }
  7. .......
  8. }

DraSoftware is called at draw().
  1. private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int yoff,
  2. boolean scalingRequired, Rect dirty) {
  3. .......
  4. canvas = mSurface.lockCanvas(dirty); //Obtain and Lock Canvas Drawing Objects through Surface Objects
  5. .......
  6. mView.draw(canvas); //Drawing from DecorView, which is the root view of the whole Window s, will result in drawing the whole tree.
  7. .......
  8. surface.unlockCanvasAndPost(canvas); //Release the Canvas lock and notify Surface Flinger to update the area
  9. .......
  10. }
DraSoftware () calls mView.draw(canvas), and it's only here that you really start drawing with a brush.
View.java
  1. public void draw(Canvas canvas) {
  2. final int privateFlags = mPrivateFlags;
  3. final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
  4. (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
  5. mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
  6. /*
  7. * Draw traversal performs several drawing steps which must be executed
  8. * in the appropriate order:
  9. *
  10. * 1. Draw the background
  11. * 2. If necessary, save the canvas' layers to prepare for fading
  12. * 3. Draw view's content
  13. * 4. Draw children
  14. * 5. If necessary, draw the fading edges and restore layers
  15. * 6. Draw decorations (scrollbars for instance)
  16. */
  17. // Step 1, draw the background, if needed
  18. int saveCount;
  19. if (!dirtyOpaque) {
  20. drawBackground(canvas);//Drawing background
  21. }
  22. // skip step 2 & 5 if possible (common case)
  23. final int viewFlags = mViewFlags;
  24. boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
  25. boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
  26. if (!verticalEdges && !horizontalEdges) {//The fading Edge property is not set, and the gradient projection effect is not set.
  27. // Step 3, draw the content
  28. if (!dirtyOpaque) {
  29. onDraw(canvas);
  30. }
  31. // Step 4, draw the children
  32. dispatchDraw(canvas);
  33. // Step 6, draw decorations (scrollbars)
  34. onDrawScrollBars(canvas);
  35. if (mOverlay != null && !mOverlay.isEmpty()) {
  36. mOverlay.getOverlayView().dispatchDraw(canvas);
  37. }
  38. // we're done...
  39. return;
  40. }
  41. ...//Processing settings for gradient projection effects
  42. }
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.
  1. protected void onDraw(Canvas canvas) {
  2. if (mDivider == null) {
  3. return;
  4. }
  5. if (mOrientation == VERTICAL) {
  6. drawDividersVertical(canvas);
  7. } else {
  8. drawDividersHorizontal(canvas);
  9. }
  10. }
  11. void drawDividersVertical(Canvas canvas) {
  12. final int count = getVirtualChildCount();
  13. for (int i = 0; i < count; i++) {
  14. final View child = getVirtualChildAt(i);
  15. if (child != null && child.getVisibility() != GONE) {
  16. if (hasDividerBeforeChildAt(i)) {
  17. final LayoutParams lp = (LayoutParams) child.getLayoutParams();
  18. final int top = child.getTop() - lp.topMargin - mDividerHeight;
  19. drawHorizontalDivider(canvas, top);
  20. }
  21. }
  22. }
  23. if (hasDividerBeforeChildAt(count)) {
  24. final View child = getVirtualChildAt(count - 1);
  25. int bottom = 0;
  26. if (child == null) {
  27. bottom = getHeight() - getPaddingBottom() - mDividerHeight;
  28. } else {
  29. final LayoutParams lp = (LayoutParams) child.getLayoutParams();
  30. bottom = child.getBottom() + lp.bottomMargin;
  31. }
  32. drawHorizontalDivider(canvas, bottom);
  33. }
  34. }

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
http://liguanyi11111.iteye.com/blog/2100535
draw process analysis in Android (combined with the latest Android 4.0.4 source code)
http://blog.csdn.net/zjmdp/article/details/7713963

Posted by kazil on Thu, 28 Mar 2019 05:12:30 -0700