Measure过程:
View方法:
1.public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
………..
int cacheIndex = forceLayout ? -1 :mMeasureCache.indexOfKey(key);
if (cacheIndex < 0 || sIgnoreMeasureCache) {
// measure ourselves, this should setthe 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 thehigh 32 bits, no mask needed
setMeasuredDimensionRaw((int) (value>> 32), (int) value);
mPrivateFlags3 |=PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}
………….
Measure方法时final,View的子类不允许重写该方法,在这个方法中去调用onMeasure方法
2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
Measure方法中调用setMeasuredDimension设置测量值
上述两个方法中的参数(int widthMeasureSpec, intheightMeasureSpec)都是由父容传递过来的,父容器根据自己的measureSpec和子View的layoutParams和padding和margin计算子View的measureSpec
ViewGroup方法:
1. 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);
}
}
}
该方法测量所有的子View
2.protected void measureChild(View child, intparentWidthMeasureSpec,
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);
}
该方法测量一个子View,调用子view.measure方法,子View的measureSpec计算方法getChildMeasureSpec
3. protected void measureChildWithMargins(View child,
int parentWidthMeasureSpec, intwidthUsed,
int parentHeightMeasureSpec, intheightUsed) {
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);
}
也是测量子View,这个方法考虑到padding和margin,ViewGroup是一个抽象类,没有
重写onMeasure方法,这是因为ViewGroup的子类具有不同的布局特性,每个子类的测量细节也不同,由它的子类,如LinearLayout,RelativeLayout去重写onMeasure方法
LinearLayout方法:
LinearLayout继承自ViewGroup
1. @Override
protected void onMeasure(intwidthMeasureSpec, int heightMeasureSpec) {
if (mOrientation == VERTICAL) {
measureVertical(widthMeasureSpec,heightMeasureSpec);
} else {
measureHorizontal(widthMeasureSpec, heightMeasureSpec);
}
}
分为水平方向和竖直方向两种情况,下面看一下竖直方向
2. voidmeasureVertical(int widthMeasureSpec, int heightMeasureSpec) {
………
final int usedHeight = totalWeight == 0 ?mTotalLength : 0;
measureChildBeforeLayout(child, i, widthMeasureSpec, 0,
heightMeasureSpec, usedHeight);
final int childHeight = child.getMeasuredHeight()
……