protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
int size = Math.min(width, height);
setMeasuredDimension(size, size);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = (int) ((PADDING + RADIUS) * 2);
int height = (int) ((PADDING + RADIUS) * 2)
setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec,0),
resolveSizeAndState(height, heightMeasureSpec, 0));
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
Rect childBounds = childrenBounds[i];
// 测量⼦ View
measureChildWithMargins(child, widthMeasureSpec,
widthUsed,
heightMeasureSpec, heightUsed);
// 保存⼦ View 的位置和尺⼨
childBounds.set(childlLeft, childTop, childLeft
+ child.getMeasuredWidth(), chiltTop
+ child.getMeasuredHeight());
......
}
// 计算⾃⼰的尺⼨,并保存
int width = ...;
int height = ...;
setMeasuredDimension(resolveSizeAndState(width,widthMeasureSpec, 0),resolveSizeAndState(height, heightMeasureSpec,0));
}
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);
}
MeasureSpec.makeMeasureSpec(size, mode)
来求得结果: 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:
if (childDimension >= 0) {
// Child wants a specific size... so be it
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size, but our size is not fixed.
// Constrain child to not be bigger than us.
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
} 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 asked to see how big we want to be
case MeasureSpec.UNSPECIFIED:
if (childDimension >= 0) {
// Child wants a specific size... let him have it
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size... find out how big it should
// be
resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
resultMode = MeasureSpec.UNSPECIFIED;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size.... find out how
// big it should be
resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
resultMode = MeasureSpec.UNSPECIFIED;
}
break;
}
//noinspection ResourceType
return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}
注意:源码中的分类⽅式是先⽐较⾃⼰的 MeasureSpec 中的 mode,再 ⽐较开发者设置的 layout_width 和 layout_height,⽽我给出的判断⽅式 (下⾯的这⼏段内容)是先⽐较 layout_width 和 layout_height,再⽐较 ⾃⼰ MeasureSpec 中的 mode。两种分类⽅法都能得出正确的结果,但 源码中的分类⽅法在逻辑上可能不够直观,如果你读源码理解困难,可以 尝试⽤我上⾯的这种⽅法来理解。
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
Rect childBounds = childrenBounds[i];
// 将每个⼦ View 的位置和尺⼨传递给它
child.layout(childBounds.left, childBounds.top,
childBounds.right, childBounds.bottom);
}
}