@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// For simple implementation, our internal size is always 0.
// We depend on the container to specify the layout size of
// our view. We can't really know what it is since we will be
// adding and removing different arbitrary views and do not
// want the layout to change as this happens.
setMeasuredDimension(getDefaultSize(0, widthMeasureSpec),
getDefaultSize(0, heightMeasureSpec));
}
在ViewPager的onMeasure()中直接调用getDefaultSize(), 而该方法在AT_MOST 和EXACTLY模式下,高度为match_parent, 所以在ViewPager中设置wrap_content会失效,默认为match_parent.
public static int getDefaultSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
如何保证wrap_content 有效,可以去重写ViewPager的onMeasure() 方法,主动去测量子View的高度;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//所有子View高度的最大值
int height = 0;
//下面遍历所有child的高度
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
//网络上的错误做法
//child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
ViewGroup.LayoutParams params = child.getLayoutParams();
int childWidthMeaSpec = getChildMeasureSpec(widthMeasureSpec,
getPaddingLeft() + getPaddingRight(), params.width);
int childHeightMeaSpec = getChildMeasureSpec(heightMeasureSpec,
getPaddingTop() + getPaddingBottom(), params.height);
child.measure(childWidthMeaSpec, childHeightMeaSpec);
int h = child.getMeasuredHeight();
if (h > height) height = h;
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
最后需要注意的是,在构建Fragment请时使用inflate的三个参数的方法,即
// 同样会导致高度失效
inflater.inflate(R.layout.fragment_lazy,null)
//正确使用
inflater.inflate(R.layout.fragment_lazy,container,false)
因为在inflate()方法中会根据设置root和attachToRoot两个值来构建LayoutParams, 使得设置的高度有效。
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
....
ViewGroup.LayoutParams params = null;
if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);
}
}
.....
}