1. Measurement process

  1. The parent View in its onMeasure(), according to the developer declared in XML layout_width, layout_height, and its own available space, the specific size requirements for the child View
  2. The subview calculates its desired size according to its own characteristics in its onMeasure()
    1. In the case of a ViewGroup, the measure() of each child View is also called here
  3. After the parent View calculates the desired size of the child View, the parent View obtains the actual size and position of the child View
  4. In its own layout() method, the child View saves its actual size and position as passed in by the parent View
    1. In the case of a ViewGroup, onLayout() calls the layout() of each word of the View and passes its size to them

2. Specific development process

  1. Override onMeasure ()
  2. Get the measured size with getMeasuredWidth() and getMeasuredHeight()
  3. Calculate the final size you want
  4. Save the results with setMeasuredDimension(Width, height)

3.mode

  • EXACTLY in this mode, the component is EXACTLY as wide or as long as the value of size is. The top two digits of 01 mean ‘exact mode’. The MeasureSpec. EXACTLY
  • The size of the parent component is as large as it can be. The size of the current component can be as large or as small as this. The highest two digits are 11 for maximum mode. The MeasureSpec. AT_MOST
  • UNSPECIFIED mode (MeasureSpec.UNSPECIFIED) This means that the current component can use UNSPECIFIED space. The highest two digits of 00 indicate “unspecified mode”. The MeasureSpec. UNSPECIFIED

4.measure()

  • Method scheduling for onMeasure() is implemented in measure()
  • The measurement result is cached by mMeasureCache, and the structure is key-value
  • If the PFLAG_MEASURED_DIMENSION_SET flag is not set, an exception must be raised, and setMeasuredDimensionRaw(XX) must be used to measure the View.

Source process

  1. If the result of this measurement is different from that of the last one, it indicates that the size has changed, and a new layout is required if one of the following three conditions is met
    1. Is it Exactly mode?
    2. Is the size currently measured consistent with the size given by the parent layout
    3. Below 6.0, sAlwaysRemeasureExactly=true
  2. If you need to rewrite the layout, enter the following logic:
    1. First empty the label PFLAG_MEASURED_DIMENSION_SET (Measured value recorded)
    2. Try to get results from the cache (no forced relayout case)
      1. OnMeasure () is called if there is no cache
      2. If there is a cache, fetch the cache directly
  3. Record the final measurement results and add them to the cache

5. Viewgroup.onmeasure () implementation process

  1. Iterate over the sub View and call measureChildWithMargins()
    1. Call getChildMeasureSpec() to get the measure of the child View, the measurement result of the parent View, the width and height used, and the LayoutParams of the child View
      1. The computed results, through the MeasureSpec. MakeMeasureSpec resultSize, resultMode encapsulate
    2. MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = Measure(
  2. The measurement results were recorded by the resolveSizeAndState() method

5.1 measureChildWidthMargins ()

  1. Iterate over each child View, measuring the child View with measureChildWidthMargins()

    To use the measureChildWithMargins() method, you need to override generateLayoutParams() and return MarginLayoutParams

    Some child Views may need to be remeasured (e.g. at line breaks)

    After the measurement is completed, the actual position and size of the sub-view are obtained and temporarily saved

  2. WidthMeasureSpec (int Spec, int padding, int childDimension); Then call the child.measure() method to make the child View measure itself

Source process

  1. If the developer writes a specific value (for example, layout_width=”24dp”), then the parent View will not have to worry about the remaining space of the parent View and will use layoutparams.width/height to limit the size of the child View. Restrict mode to EXACTLY

  2. If the developer is writing MATCH_PARENT, the widthMeasureSpec or heightMeasureSpec mode is the case

    1. If the mode in your spec is EXACTLY or AT_MOST, you have an upper limit on the size of your View. Subtract your used width or height from the size of your spec.
      1. If its own mode is EXACTLY, the mode passed to the child View is EXACTLY
      2. If its mode is AT_MOST, the mode passed to the child View is AT_MOST
    2. The mode of the spec is UNSPECIFIED, which means that the size of the spec is UNSPECIFIED. The mode limiting child View is set to UNSPECIFIED with size 0
  3. WidthMeasureSpec and heightMeasureSpec modes are used to measure widthMeasureSpec and heightMeasureSpec modes.

    1. If the mode in your spec is EXACTLY or AT_MOST, you have an upper limit on the size of your sub-view. For mode, use AT_MOST

      Note that even if your mode is EXACTLY the same, the child View is AT_MOST,

    2. The mode of the spec is UNSPECIFIED, which means that the size of the spec is UNSPECIFIED. The mode limiting child View is set to UNSPECIFIED with size 0

5.2 resolveSizeAndState ()

MeasureSpec. GetMode (MeasureSpec) and MeasureSpec. GetSize (MeasureSpec)

  1. If mode is EXACTLY, it means that the parent View has made an exact limit on the child View’s size, so the calculated size is abandoned and the measure Spec size is used directly
  2. If mode is AT_MOST, the parent View limits the size of its child View.
    1. If the calculated size is not greater than the size limit specified in the spec, it means that the size limit has not been exceeded, so use the calculated size.
    2. If the calculated size is greater than the size limit in the spec, it means that the size limit is exceeded. Therefore, the size of the spec is selected. The MEASURED_STATE_TOO_SMALL flag will be added to resolveSizeAndState() (this flag helps the parent View do measurement and layout calculations)
  3. The Mode is UNSPECIFIED, which means that the parent View has no size restrictions on its child views, so the calculated size is used instead of the size in the spec.

6. View.onmeasure () default implementation process

  1. Use getDefaultSize() to compare the minimum size to the size passed in by the parent View to find the appropriate size
  2. The measured dimensions are recorded by setMeasuredDimension() and marked as measured by PFLAG_MEASURED_DIMENSION_SET

7. ViewGroup/View onMeasure ()

  • View onMeasure() is responsible for recording the measurement results given by the ViewGroup into member variables after some tradeoffs
  • ViewGroup onMeasure() first iterates through the measurement of its child layout, and then records the measured size value into the member variable based on the measurement result of the child layout and the measurement result given by its parent layout after some tradeoff
  • Inheriting from ViewGroup, the onMeasure() method must be overridden to measure the result for the inside child layout

8. Why is onMeasure() executed more than once?

  • First, when the screen refresh signal arrives, the performTraversals() method is executed to enable measurement, layout, and rendering

  • The measureHierarchy() method is called within the performTraversals() method for the overall measurement

  • Whereas in measureHierarchy(), there are three measurements, and the code implementation calls performMeasure() three times.

    • The first time: use the pre-set width and height to measure the ViewTree and get the measurement results
    • Second time: If there is a View that is larger than the preset width and height, the condition is not met. Therefore, a larger width and height is set for the second measurement
    • Third time: If the enlarged measurement result is not satisfied, measure again with the largest size window can get

    Every time performMeasure() starts onMeasure()

  • PerformMeasure () will be called once after measureHierarchy() completes

    • However, this measurement will only be carried out when:
    • It’s executed the first time you show the View
    • Window size changes are executed

    This step may not be executed later when triggered by requestLayout(), so onMeasure() may only be executed once

8.1 Why is it designed like this?

  • The measurement in measureHierarchy() is to obtain the RootView measurement, which is used in relayoutWindow() to re-determine the width and height of the Window
  • Subsequent measurements are performed after relayoutWindow()