在开发过程中,遇到了一个问题:将RelativeLayout
的高度从固定值180dp,修改为wrap_content
+ minHeight
之后,高度为match_parent
的子View LinearLayout
在测量后就会变成wrap_content
。
1 | <!-- item.xml --> |
经过分析,原因如下:
因为该RelativeLayout
是作为RecyclerView
的item
被使用的,来看一下RecyclerView
的getChildMeasureSpec(int, int, int, boolean)
方法:
1 | public static int getChildMeasureSpec(int parentSize, int padding, int childDimension, |
通过上述代码,可以看出,RecyclerView
在measure item的时候,传递了一个由 size = 0, measureSpecMode = UNSPECIFIED
生成的measureSpec
。接下来看一下RelativeLayout
的onMeasure(int, int)
方法:
1 |
|
结合RecyclerView
代码可知,myHeight = -1
。再看measureChild(View, LayoutParams , int, int)
方法:
1 | private void measureChild(View child, LayoutParams params, int myWidth, int myHeight) { |
继续追踪getChildMeasureSpec(int, int, int, int, int, int, int, int)
方法:
1 | private int getChildMeasureSpec(int childStart, int childEnd, |
从上述分析,我们了解了产生bug的原因。那么是否有可能修复这个bug?
前面代码分析中,写了一句“此处似乎隐含修复bug的可能”,是否真的有可能呢?让我们重新分析一下applyVerticalSizeRules(LayoutParams, int, int)
方法:
1 | private void applyVerticalSizeRules(LayoutParams childParams, int myHeight, int myBaseline) { |
经过上述分析,在现有布局条件下,无法通过为子View增加一些rules来修复这个bug。只能通过布局调整来修复。
总结
这个bug实际上是普遍存在的。如果要求RecyclerView
的itemView的子view的高度是match_parent,应该尽可能避免使用RelativeLayout
的layout_height="match_parent" minHeight="xxxdp"
的写法,或者使用其他Layout。
说明
本文援引的源码如下: