我们项目中经常可能会用到类似的以下布局。
在这种情况下,RecyclerView会经常无法测量出来实际的高度,我一开始以为RecyclerView类似于ListView对MeasureSpec.UNSPECIFIED做了直接高度处理而无法正确测量,但我查看源码后发现不是这样的。网上查找的解决方法是嵌套RelativeLayout。那么为什么RelativeLayout能正确测量而LinearLayout却不行呢,直接查看源码来简单了解一下。
一、ScrollView的onMeasure
首先我们查看ScrollView的onMeasure方法。onMeasure调用了super,然后走到measureChildWithMargins()
@Override
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 usedTotal = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin +
heightUsed;
final int childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
Math.max(0, MeasureSpec.getSize(parentHeightMeasureSpec) - usedTotal),
MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
这里我们只关注这里
final int childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
Math.max(0, MeasureSpec.getSize(parentHeightMeasureSpec) - usedTotal),
MeasureSpec.UNSPECIFIED);
childHeightMeasureSpec 也就是mode是UNSPECIFIED,size是ScrollView的高度,这里usedTotal=0。
二、LinearLayout的OnMeasure
说实话LinearLayout的OnMeasure真的相当的长,但是我们也只需要找关键的地方,weight的处理可以暂时不用管。
在measureVertical()方法中我们直接找到测量规格是如何传入子View的。
final int usedHeight = totalWeight == 0 ? mTotalLength : 0;
measureChildBeforeLayout(child, i, widthMeasureSpec, 0,heightMeasureSpec, usedHeight);
其实我可以按照实现的情况来猜测,其实就是将LinearLayout的测量规格加上child已经使用的控件来综合判断下一个child是什么规格的。我接着看源码。
直接调用了ViewGroup的measureChildWithMargins
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);
}
那么根据实际情况就可以再猜测这个方法get