This is the 17th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021
MeasureSpec
MeasureSpec is a class that is composed of MODE_MASK and MODE_SHIFT a 32-bit int value, the former two code SpecMode, 30 represents SpecSize behind. SpecMode indicates the measurement mode; SpecSize indicates the size of the specification in a certain measurement mode.
public static class MeasureSpec {
private static final int MODE_SHIFT = 30;
private static final int MODE_MASK = 0x3 << MODE_SHIFT;
/ * *@hide* /
@IntDef({UNSPECIFIED, EXACTLY, AT_MOST})
@Retention(RetentionPolicy.SOURCE)
public @interface MeasureSpecMode {}
public static final int UNSPECIFIED = 0 << MODE_SHIFT;
public static final int EXACTLY = 1 << MODE_SHIFT;
public static final int AT_MOST = 2 << MODE_SHIFT;
public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
@MeasureSpecMode int mode) {
if (sUseBrokenMakeMeasureSpec) {
return size + mode;
} else {
return(size & ~MODE_MASK) | (mode & MODE_MASK); }}@UnsupportedAppUsage
public static int makeSafeMeasureSpec(int size, int mode) {
if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) {
return 0;
}
returnmakeMeasureSpec(size, mode); }}Copy the code
SpecMode
The SpecMode modes are UNSPECIFIED, EXACTLY, and AT_MOST. All three modes are obtained by bit operation.
- UNSPECIFIED
UNSPECIFIED indicates that the parent container has no restrictions on the View, and the View can set its own size. Does not need the developer to care, by the system internal call. For example, the ScrollView view.
- EXACTLY
EXACTLY means that the parent container has measured the required size of the View. MeasureSpec SpecSize corresponds to LayoutParams’ match_parent and the specified value.
- AT_MOST
AT_MOST indicates that the parent container tops the available size SpecSize. The size of the View is within this value range. SpecSize in MeasureSpec corresponds to WRAP_content in LayoutParams.
Relationship between LayoutParams and MeasureSpec
MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec = MeasureSpec A MeasureSpec is determined by LayoutParams and the parent container.
A DecorView’s MeasureSpec is calculated slightly differently from a normal View’s. A DecorView’s MeasureSpec is determined by the screen size and LayoutParams. Its default LayoutParams is match_parent. For a normal View, MeasureSpec is determined by the parent container’s MeasureSpec and its own LayoutParams.
MeasureSpec create
LayoutParams influence
In ViewRootImpl, getRootMeasureSpec is executed in the measureHierarchy method, which evaluates the View’s MeasureSpec. The MeasureSpec creation logic is clear from getRootMeasureSpec.
###ViewRootImpl.measureHierarchy
private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {... childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width); childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height); . } ###ViewRootImpl.getRootMeasureSpec
private static int getRootMeasureSpec(int windowSize, int rootDimension) {
int measureSpec;
switch (rootDimension) {
case ViewGroup.LayoutParams.MATCH_PARENT:
// Window can't resize. Force root view to be windowSize.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
break;
case ViewGroup.LayoutParams.WRAP_CONTENT:
// Window can resize. Set max size for root view.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
break;
default:
// Window wants to be an exact size. Force root view to be that size.
measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
break;
}
return measureSpec;
}
Copy the code
Create different MeasureSpec’s based on the View’s LayoutParams property in the getRootMeasureSpec method.
- LayoutParams.MATCH_PARENT
Exact mode, size is the size of the parent container window.
- LayoutParams.WRAP_CONTENT
The size is indeterminate but does not exceed the maximum size of the parent container window.
- default
Default is not set, the precise mode size is determined by the set size.
The parent container ViewGroup is affected
On the ViewGroup, there is a method measureChildWithMargins that calculates the size of the child View. The child View’s MeasureSpec is calculated using getChildMeasureSpec before calling child.measure(). The parent container affects the size calculation of the child View.
protected void measureChildWithMargins(View child,
int parentWidthMeasureSpec, int widthUsed,
int parentHeightMeasureSpec, int heightUsed) {
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
+ widthUsed, lp.width);
final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
+ heightUsed, lp.height);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
Copy the code
The ViewGroup’s getChildMeasureSpec method calculates the child View’s SpecMode by obtaining the parent’s SpecMode and then calculating the child View’s SpecMode through the child View’s LayoutParams. Finally through the MeasureSpec. MakeMeasureSpec (resultSize resultMode) method of the View MeasureSpec.
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
int specMode = MeasureSpec.getMode(spec);
int specSize = MeasureSpec.getSize(spec);
int size = Math.max(0, specSize - padding);
int resultSize = 0;
int resultMode = 0;
switch (specMode) {
// Parent has imposed an exact size on us
case MeasureSpec.EXACTLY:
if (childDimension >= 0) {
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size. So be it.
resultSize = size;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size. It can't be
// bigger than us.
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
}
break;
// Parent has imposed a maximum size on us
case MeasureSpec.AT_MOST:
....../ / same as above
// Parent asked to see how big we want to be
case MeasureSpec.UNSPECIFIED:
....../ / same as above
break;
}
//noinspection ResourceType
return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}
Copy the code
Child View Size/ parent SpecMode | EXACTLY | AT_MOST | UNSPECIFIED |
---|---|---|---|
Specific size setting | EXACTLY | EXACTLY | EXACTLY |
match_parent | EXACTLY | AT_MOST | UNSPECIFIED |
wrap_content | AT_MOST | AT_MOST | UNSPECIFIED |
- When a child View is set to a specific size, whatever the parent SpecMode is, the child View’s SpecMode is EXACTLY the same.
- The child View size is match_parent, and the child View’s SpecMode is the parent’s SpecMode. The size is the maximum remaining size of the parent container.
- The size of the child View is WRap_content and the SpecMode of the child View is AT_MOST. UNSPECIFIED only if the parent SpecMode is UNSPECIFIED and the child View has LayoutParams set.