项目中用到动态高度的ViewPager,为了加强记忆,自己也仿着写个效果来
原理:
ViewPager默认是每个页面相同高度的,我们要改变其页面的高度,
自然就要在其显示某个页面的时候调用其(ViewPager)的onMeasure方法。
本文基于这个观点,在每次选择页面后将当前页面(Fragment)的rootView传递到ViewPager中,
让ViewPager根据该rootView,一般是ViewGroup类型,去重新执行onMeasure方法
1、传递给ViewPager中页面的rootView;
2、ViewPager获取到rootView后调用requestLayout方法使ViewPager再次调用onMeasure方法
3、重写ViewPager的onMeasure方法,根据rootView获取其总高度,传递给ViewPager
先上布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
我图省事,没有新建Activity,是在Fragment中测试的,所以这个布局是Fragment的布局
ViewPager的代码
public class DynamicHeightViewPager extends ViewPager {
private ViewGroup mContainer;
public DynamicHeightViewPager(@NonNull Context context) {
super(context);
}
public DynamicHeightViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public void measuredCurrentView(ViewGroup viewGroup){
this.mContainer = viewGroup;
requestLayout();//重新布局,触发onMeasure
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mContainer == null) {//ViewPager自动绘制是调用默认的即可
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
int height = 0;//以下为测量rootView高度传递给viewPager
for (int i = 0; i < mContainer.getChildCount(); i++) {
View child = mContainer.getChildAt(i);
if (child != null) {
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
height += child.getMeasuredHeight();
}
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
}
}
测试代码
mAdapter = new TabAdapter(getChildFragmentManager());
mViewPager.setAdapter(mAdapter);
mTabLayout.setupWithViewPager(mViewPager);
//to measure height realize dynamic height
mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
if (position > mAdapter.getCount() || mViewPager == null || mHeader == null)
return;
MyContentFragment fragment = (MyContentFragment) mAdapter.getItem(position);
mViewPager.measuredCurrentView(fragment.getContainer());
ViewGroup.LayoutParams params = mHeader.getLayoutParams();
}
});
//coordinate the onPageSelected,the first show time is called
mViewPager.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
MyContentFragment fragment = (MyContentFragment) mAdapter.getItem(0);
if (mViewPager != null && fragment != null && mHeader != null) {
mViewPager.measuredCurrentView(fragment.getContainer());
}
if (mViewPager != null && mViewPager.getViewTreeObserver() != null) {
mViewPager.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
});
class TabAdapter extends FragmentPagerAdapter {
TabAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
@Override
public int getCount() {
return mFragments.size();
}
}
注:其中 1、mViewPager.addOnPageChangeListener()方法是在ViewPager滑动的时候触发,此时我们将rootView传递到ViewPager中,使ViewPager重新测量高度;但是 2、OnPagerChangeListener方法在ViewPager第一次显示时不会触发,通过mViewPager.getViewTreeObserver().addOnGlobalLayoutListener()方法可以在整个布局layout结束后调用,从而实现ViewPager显示出来就会被我们重新调用onMeasure方法,实现动态改变高度
通过两个监听结合可以实现对ViewPager切换和初始获取,动态改变为我们的高度