Summary of Android's dominant control View

Summary of Android's dominant control View

[[163808]]

About Android View Controls

Controls in Android are roughly divided into two categories: ViewGroup and View. ViewGroup manages View as a container. Android view is a structure similar to the DOM tree. The parent view is responsible for measuring, positioning, drawing and other operations. The reason why the findViewById method we often use is expensive is because it is responsible for traversing the entire control tree from top to bottom to find the View instance. Try to use it as little as possible in repeated operations. Many controls currently in use are directly or indirectly inherited from View, as shown in the figure below.

View inheritance tree

Android UI interface architecture

Each Activity contains a PhoneWindow object, and PhoneWindow sets DecorView as the root view of the application window. Inside it are the familiar TitleView and ContentView. Yes, the setContentView() that we usually use is the ContentView that is set.

UI Architecture

How does Android draw View?

When an Activity is started, it will be asked to draw its layout. The Android framework will handle this request, of course, the premise is that the Activity provides a reasonable layout. Drawing starts from the root view and traverses the entire view tree from top to bottom. Each ViewGroup is responsible for drawing its own child Views, and each View is responsible for drawing itself. The drawing process is divided into three steps through the draw() method.

  • Measure
  • Layout
  • Draw

The entire drawing process is carried out in the performTraversals() method in ViewRoot. Part of the source code is as follows.

  1. private   void performTraversals() {
  2. ......
  3. //The origin of widthMeasureSpec and heightMeasureSpec of the outermost root view  
  4. //lp.width and lp.height are equal to MATCH_PARENT when creating a ViewGroup instance  
  5. int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
  6. int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
  7. ......
  8. mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
  9. ......
  10. mView.layout( 0 , 0 , mView.getMeasuredWidth(), mView.getMeasuredHeight());
  11. ......
  12. mView.draw(canvas);
  13. ......
  14. }

Of course, you need to know the size and drawing of the view before drawing. So first do measurement and layout (measurement and positioning), as shown below.

Drawing process

Measure process

  1. public   final   void measure( int widthMeasureSpec, int heightMeasureSpec) {
  2. //....  
  3.  
  4. //Callback onMeasure() method  
  5. onMeasure(widthMeasureSpec, heightMeasureSpec);
  6.  
  7. //more  
  8. }

Calculate the actual size of the view, get the height and width and store them in mMeasuredHeight and mMeasureWidth, the two parameters passed in by measure(int, int). MeasureSpec is a 32-bit int value, the upper 2 bits are the measurement mode, and the lower 30 bits are the measured size. The measurement modes can be divided into the following three types.

  • EXACTLY
    Exact value mode. When layout_width or layout_height is specified as a specific value, or match_parent, the system uses EXACTLY.

  • AT_MOST
    Maximum value mode, when specified as wrap_content, the size of the control cannot exceed the maximum size allowed by the parent control.

  • UNSPECIFIED
    Without specifying a measurement mode, the View can be as large as you want. This is generally not used.

According to the source code above, the measure method cannot be overridden. The onMeasure method needs to be overridden during customization.

  1. protected   void onMeasure( int widthMeasureSpec, int heightMeasureSpec) {
  2. setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
  3. getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
  4. }

Looking at the source code, we can see that the final height and width are set by calling setMeasuredDimension(). If not overridden, the default is to directly call getDefaultSize to get the size.

Use the getMeasuredWidth() and getMeasuredHeight() methods of View to obtain the width and height measured by the View. These two methods must be called after the onMeasure process to return valid values.

Layout Process

The Layout method is used to determine the position of the view layout, just like after you know the size of an object, you always need to know the position before you can draw it.

  1. mView.layout( 0 , 0 , mView.getMeasuredWidth(), mView.getMeasuredHeight());

layout takes four parameters, the left, top, right, and bottom coordinates, relative to the parent view. Here you can see that the width and height just measured are used.

  1. public   void layout( int l, int t, int r, int b) {
  2. int oldL = mLeft;
  3. int oldT = mTop;
  4. int oldB = mBottom;
  5. int oldR = mRight;
  6. boolean changed = setFrame(l, t, r, b);
  7. if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) {
  8. .....
  9. onLayout(changed, l, t, r, b);
  10. .....
  11. }

Set the coordinates via setFrame. If the coordinates have changed, reposition them. If it is a View object, onLayout is an empty method because the positioning is determined by ViewGroup.

getWidth() and getHeight() will return the correct values ​​only after layout is completed.

A question arises here, what is the difference between getWidth/Height() and getMeasuredWidth/Height()?

  • getWidth(): The width of the View after the layout is set.
  • getMeasuredWidth(): The width of the View content obtained by measuring the content on the View.

getwidth

Draw process

  1. public   void draw(Canvas canvas) {
  2. ......
  3. /*
  4. * Draw traversal performs several drawing steps which must be executed
  5. * in the appropriate order:
  6. *
  7. * 1. Draw the background
  8. * 2. If necessary, save the canvas' layers to prepare for fading
  9. * 3. Draw view's content
  10. * 4. Draw children
  11. * 5. If necessary, draw the fading edges and restore layers
  12. * 6. Draw decorations (scrollbars for instance)
  13. */  
  14.  
  15. // Step 1, draw the background, if needed  
  16. ......
  17. if (!dirtyOpaque) {
  18. drawBackground(canvas);
  19. }
  20.  
  21. // skip step 2 & 5 if possible (common case)  
  22. ......
  23.  
  24. // Step 2, save the canvas' layers  
  25. ......
  26. if (drawTop) {
  27. canvas.saveLayer(left, top, right, top + length, null , flags);
  28. }
  29. ......
  30.  
  31. // Step 3, draw the content  
  32. if (!dirtyOpaque) onDraw(canvas);
  33.  
  34. // Step 4, draw the children  
  35. dispatchDraw(canvas);
  36.  
  37. // Step 5, draw the fade effect and restore layers  
  38. ......
  39. if (drawTop) {
  40. matrix.setScale( 1 , fadeHeight * topFadeStrength);
  41. matrix.postTranslate(left, top);
  42. fade.setLocalMatrix(matrix);
  43. p.setShader(fade);
  44. canvas.drawRect(left, top, right, top + length, p);
  45. }
  46. ......
  47.  
  48. // Step 6, draw decorations (scrollbars)  
  49. onDrawScrollBars(canvas);
  50. ......
  51. }

The key point is to call the onDraw method in the third step. The other steps are to draw some corners such as background, scrollBar, etc. Among them, dispatchDraw is used to recursively call the child View, and it is not needed if there is no child View.

The onDraw method needs to be implemented by yourself, because the content drawn by each control is different. It is mainly drawn with the canvas object, so I won't talk about it here.

References

  1. A complete analysis of the Android view drawing process, taking you step by step to understand View (Part 2)
  2. Android application layer View drawing process and source code analysis
  3. How Android Draws Views
  4. Android Heroes
  5. What is the difference between getWidth/Height() and getMeasuredWidth/Height() in Android SDK?

<<:  The essence of architecture, the way among thousands of methods

>>:  15 interesting facts about mobile apps

Recommend

Mr. Yuan Haotong – Mixing and post-production

Teacher Yuan Haotong - Introduction to mixing and...

PS Advanced Course: Commercial Product Refinement + Poster Synthesis

PS Advanced Course: Commercial Product Refinement...

Why don’t many companies use WeChat for Business, DingTalk and Lark?

In the field of enterprise instant messaging, WeC...

Why is gold, a precious metal, so valuable? | Science Gallery

Creator: China Digital Science and Technology Mus...