这几天做一个页面,需要用到ScrollView嵌套ViewPager,而ViewPager(Fragment)中又有两个Fragment 分别包含ListView以及WebView,大概的层级是这样的:
这样布局就会导致Viewpager WebView ListView 三个控件都显示不出来,导致这样的原因是,在Measure流程的时候,不能测出这三个控件的宽高,导致这三个控件不能显示,说到Measure 大家应该都知道该怎么解决了吧,没错,就是重写这三个控件的onMeasure方法,我们先来看看重写的ViewPager,当然重写ViewPager的方法,网上也有很多,就是关于这个问题的。大家,也可以去看看别人的博客,下面贴代码:
public class AutofitHeightViewPager extends ViewPager { private int current; private int height = 0; /** * 保存position与对于的View */ private HashMap<Integer, View> mChildrenViews = new LinkedHashMap<Integer, View>(); private boolean scrollble = true; private static final String TAG = "AutofitHeightViewPager"; public AutofitHeightViewPager(Context context) { super(context); } public AutofitHeightViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mChildrenViews.size() > current) { View child = mChildrenViews.get(current); child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); height = child.getMeasuredHeight(); } heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } public void resetHeight(int current) { this.current = current; if (mChildrenViews.size() > current) { RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams(); if (layoutParams == null) { layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, height); } else { layoutParams.height = height; } Log.d(TAG, "resetHeight: "+height); setLayoutParams(layoutParams); } } /** * 保存position与对于的View */ public void setObjectForPosition(View view, int position) { mChildrenViews.put(position, view); }
说好重写onMeasure 方法,怎么还多了两个方法呢?
如果只重写onMeasure方法,看看onMeasure方法,你会发现,在方法中,为了所Fragment都能显示完全,只会选择最大值,来作为ViewPager的总高度,那么,高度较小的那个Fragment下方就会留出很多空白,这样非常不美观,最好的办法就是动态设置当前ViewPager的高度。下面我们看看多出来的方法,是用来干嘛的。
setObjectForPosition:将当前的Fragment传递到类开头声明的成员中,建议在初始化Fragment的时候调用一下这个方法,将Fragment存入到当前的自定义的ViewPager中,以便后面使用,Position是查找对应Fragment的Key。
resetHeight:传入当前ViewPager显示的页面下标,获取到当前的Fragment的实际高度,设置为当前ViewPager的高度,这个方法建议设置ViewPager的页面切换监听,来实现设置不同高度。
当然,光重写ViewPager是不行的,还需要将 ViewPager 中对应加载的控件的onMeasure都重写,
ListView:
public class AutoFitHeightListView extends ListView { public AutoFitHeightListView(Context context) { super(context); } public AutoFitHeightListView(Context context, AttributeSet attrs) { super(context, attrs); } public AutoFitHeightListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int mExpandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, mExpandSpec); } }
WebView:
public class AutoFitHeightWebView extends WebView { @SuppressLint("NewApi") public NoScrollWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } public NoScrollWebView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public NoScrollWebView(Context context, AttributeSet attrs) { super(context, attrs); } public NoScrollWebView(Context context) { super(context); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int mExpandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, mExpandSpec); } }
这两个就只要重写哦你Measure方法就可以了,到这就差不多了。
剩下的就是在项目中,把控件都换成自定义的控件就好了。