This is the 18th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

Measure the process

The View of the measure

The measure method in a View calculates the size of the View. The onMeasure method is called in the measure method. The core of calculating dimensions is in the onMeasure method.

public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
    boolean optical = isLayoutModeOptical(this); .if (forceLayout || needsLayout) {
        // first clears the measured dimension flag
        mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
        resolveRtlPropertiesIfNeeded();
        int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
        if (cacheIndex < 0 || sIgnoreMeasureCache) {
            // measure ourselves, this should set the measured dimension flag back
            onMeasure(widthMeasureSpec, heightMeasureSpec);
            mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
        } else {
            long value = mMeasureCache.valueAt(cacheIndex);
            // Casting a long to int drops the high 32 bits, no mask needed
            setMeasuredDimensionRaw((int) (value >> 32), (int) value); mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; }... }Copy the code

Focus on the setMeasuredDimension and getDefaultSize methods in the onMeasure method. SetMeasuredDimension sets the width and height of the View. When specMode is MeasureSpec.AT_MOST and MeasureSpec.EXACTLY, the size returned by getDefaultSize is the measured size. With MeasureSpec.UNSPECIFIED mode, the View size is normally used for internal measurements from the system, and is the returned value from the system Getmanaged Minimum. From the getSuggestedMinimum method, the View size was mMinWidth when the mBackground Drawable parameter was not set to the View, and mMinWidth corresponds to the minimum width that was set to, which is then defaults to 0. When the View has set the background, according to the method of Max (mMinWidth, mBackground getMinimumWidth ()) to calculate the maximum width as the size of the View.

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
            getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
public static int getDefaultSize(int size, int measureSpec) {
    int result = size;
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);

    switch (specMode) {
    case MeasureSpec.UNSPECIFIED:
        result = size;
        break;
    case MeasureSpec.AT_MOST:
    case MeasureSpec.EXACTLY:
        result = specSize;
        break;
    }
    return result;
}

protected int getSuggestedMinimumWidth(a) {
    return (mBackground == null)? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); }Copy the code

The measure of ViewGroup

The ViewGroup’s measure procedure has more traversal calls to subviews. In addition to calling its own measure methods, the ViewGroup also iterates through the measure methods that call its child views.

The child View’s MeasureSpec and LayoutParams are passed as parameters to the getChildMeasureSpec method. Finally, measure method is used to calculate the child View with child View’s MeasureSpec.

# ViewGroup. MeasureChildren / / traversal calculation child view protected void measureChildren (int widthMeasureSpec, int heightMeasureSpec) { final int size = mChildrenCount; final View[] children = mChildren; for (int i = 0; i < size; ++i) { final View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) ! = GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); MeasureChild (View child, int parentWidthMeasureSpec, int parentWidthMeasureSpec) int parentHeightMeasureSpec) { final LayoutParams lp = child.getLayoutParams(); final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight, lp.width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom, lp.height); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }Copy the code

Get the View width and height method

If you want to know how to get the width and height of the View when creating a View, you should know how to get the width and height of the View. If you create views in each lifecycle after the Activity starts, can you set the width and height? The View width and height may be 0 during the Activity life cycle because the View’s measure life cycle is not synchronized with the Activity life cycle. The View size can be obtained in the following ways:

  1. onWindowFocusChanged

OnWindowFocusChanged is called back after the View is initialized, and the width and height of the View have been calculated and can be obtained. But onWindowFocusChanged isn’t called just once. Called when the window gets and loses focus. You are not recommended to use this method if you have high requirements on obtaining width and height data.

  1. view.post

Implement a Runnable through Post. When the View’s Looper message queue consumes the Runnable, the View is already initialized. This method is called only once, once, and only works if the View size is not dynamically changed.

  1. ViewTreeObserver

This callback is called when the state of the View tree changes or when the View inside the View tree changes. This is a good place to get the width and height of the View and dynamically get the size of the View.