ViewPager +fragment+listview 高度适配,出现大部分空白的问题

现象:

viewpager 嵌套多个fragment。fragment中有listview。在切换的时时候,大家会遇到这种情况,listview的内容有多有少,但是viewpager都是以最高的listview的位置,这样就会导致高度比较小向上滑动的时候会出现空白。

遇到这问题,首先会想到的是ViewPager高度没有自动适配listview。那么我们首先可以根据获取fragment中listview的高度动态设置viewPager高度。

第一步自定义ViewPager。

```

/**

* 自动适应高度的ViewPager

* @author

*

*/

public class CustomViewPager extendsViewPager {

publicCustomViewPager(Context context) {

super(context);

}

public CustomViewPager(Context context, AttributeSet attrs) {

super(context, attrs);

}

@Override

protected void  onMeasure(intwidthMeasureSpec,intheightMeasureSpec) {

intheight =0;

for(inti =0; i < getChildCount(); i++) {

View child = getChildAt(i);

child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));

inth = child.getMeasuredHeight();

if(h > height)

height = h;

}

heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

}

```

这是最常见的一种处理办法,选择你fragment中高度最大的那个作为你整个viewpager的高度。解决了冲突问题,但你会遇到这样一个棘手的问题:所有viewpager中的fragment都是那个最大的高度,如果你的fragment中view的高度很小的话,或者view的高度过大的话,会导致自身或者其他fragment中出现大面积空白。所以综上所述,我们要达到的效果是去除这空白,使viewpager的高度真正“自适应”。所以进一步升级 viewpager的自定义

升级版的viewpager

```

importandroid.content.Context;

importandroid.support.v4.app.Fragment;

importandroid.support.v4.view.ViewPager;

importandroid.util.AttributeSet;

importandroid.util.TypedValue;

importandroid.view.MotionEvent;

importandroid.view.View;

importandroid.widget.LinearLayout;

importjava.util.HashMap;

importjava.util.Map;

/**

* Created by vipui on 16/8/25.

*/

public  class  CustomViewpager  extends  ViewPager {

private  int  current;

privateintheight =0;

privatebooleanscrollble =true;

publicCustomViewpager(Context context) {

super(context);

}

publicCustomViewpager(Context context, AttributeSet attrs) {

super(context, attrs);

}

@Override

protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec) {

if(getChildCount() > current) {

View child = getChildAt(current);

child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));

inth = child.getMeasuredHeight();

height = h;

}

heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

publicvoidresetHeight(intcurrent) {

this.current = current;

if(getChildCount() > current) {

LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();

if(layoutParams ==null) {

layoutParams =newLinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, height);

}else{

layoutParams.height = height;

}

setLayoutParams(layoutParams);

}

}

@Override

publicbooleanonTouchEvent(MotionEvent ev) {

if(!scrollble) {

returntrue;

}

returnsuper.onTouchEvent(ev);

}

publicbooleanisScrollble() {

returnscrollble;

}

publicvoidsetScrollble(booleanscrollble) {

this.scrollble = scrollble;

}

}

```

onMeasure()测量控件的方法,resetHeight()重置viewpager的高度的方法,从代码中可以看出在调用resetHeight()方法中传入实参current后,viewpager的高度会变成你传入实参对应下标的fragment的高度,那么在哪里调用这个方法呢?请看代码:

```

viewpager.setOnPageChangeListener(newViewPager.OnPageChangeListener() {

@Override

publicvoidonPageScrolled(intposition,floatpositionOffset,intpositionOffsetPixels) {

}

@Override

publicvoidonPageSelected(intposition) {

viewpager.resetHeight(position);

}

}

@Override

publicvoidonPageScrollStateChanged(intstate) {

}

});

activityScdetailsBottomVp.resetHeight(0);

}

```

在viewpager中的onpagerChagelistener的方法中,当你改变viewpager的pager页位置时重置viewpager的高度。好了如果你按照这个逻辑去做已经很接近实现了,但要说明一个问题,很重要的一个问题,在低版本的SDK下,似乎没什么问题,但是在高版本SDK下,就有了问题。这个问题纠结了我一天多,因为我在Android4.3的手机,完全实现了,但是在队友Android6.0的手机下就出现了问题。(这是因为高版本中viewpager有改动,并不知道有什么改动,觉得是预加载的改动)对的,高度不对应,就是你viewpager中的fragment不是自己本身的高度,可能是其他fragment的高度,这个问题,大家都应该想的到,viewpager的预加载导致的(3个或3个以上的子view),viewpager在加载当前fragment的过程中会预加载临近两个的fragment,所以,拿viewpager中有三个fragment来说,你的第一个fragment的高度是第三个fragment的高度,(因为预加载到第三个)第一你们第二个fragment的高度是你 第一个fragment的高度(预加载到第一个),以此类推。解决这个问题的方法有两个,

第一个办法:

```

activityScdetailsBottomVp.setOnPageChangeListener(newViewPager.OnPageChangeListener() {

@Override

publicvoidonPageScrolled(intposition,floatpositionOffset,intpositionOffsetPixels) {

}

@Override

publicvoidonPageSelected(intposition) {

if(position ==0) {

if(Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {

activityScdetailsBottomVp.resetHeight(1);

}else{

activityScdetailsBottomVp.resetHeight(0);

}

}elseif(position ==1) {

if(Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {

activityScdetailsBottomVp.resetHeight(2);

}else{

activityScdetailsBottomVp.resetHeight(1);

}

}else{

if(Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {

activityScdetailsBottomVp.resetHeight(0);

}else{

activityScdetailsBottomVp.resetHeight(2);

}

}

}

@Override

publicvoidonPageScrollStateChanged(intstate) {

}

});

if(Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {

activityScdetailsBottomVp.resetHeight(1);

}else{

activityScdetailsBottomVp.resetHeight(0);

}

```

简单粗暴的办法,用版本控制你要加载的页面高度,亲测可以解决,但是并不知道到了哪个高版本出现了变化,我这里用的是KITKAT(android4.4),这个临界点有待商量。那么是否会有更好的办法解决呢,这就得考虑第二种办法了,也是我使用的办法,也是自定义viewpager,大致差不多,不过也修改了不少。

第二种:

```

importandroid.content.Context;

importandroid.os.Build;

importandroid.support.v4.app.Fragment;

importandroid.support.v4.view.ViewPager;

importandroid.util.AttributeSet;

importandroid.util.TypedValue;

importandroid.view.MotionEvent;

importandroid.view.View;

importandroid.widget.LinearLayout;

importjava.util.ArrayList;

importjava.util.HashMap;

importjava.util.LinkedHashMap;

importjava.util.List;

importjava.util.Map;

/**

* Created by vipui on 16/8/25.

*/

publicclassCustomViewpagerextendsViewPager {

privateintcurrent;

privateintheight =0;

/**

* 保存position与对于的View

*/

privateHashMap mChildrenViews =newLinkedHashMap();

privatebooleanscrollble =true;

publicCustomViewpager(Context context) {

super(context);

}

publicCustomViewpager(Context context, AttributeSet attrs) {

super(context, attrs);

}

@Override

protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec) {

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);

}

publicvoidresetHeight(intcurrent) {

this.current = current;

if(mChildrenViews.size() > current) {

LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();

if(layoutParams ==null) {

layoutParams =newLinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, height);

}else{

layoutParams.height = height;

}

setLayoutParams(layoutParams);

}

}

/**

* 保存position与对于的View

*/

publicvoidsetObjectForPosition(View view,intposition)

{

mChildrenViews.put(position, view);

}

@Override

publicbooleanonTouchEvent(MotionEvent ev) {

if(!scrollble) {

returntrue;

}

returnsuper.onTouchEvent(ev);

}

publicbooleanisScrollble() {

returnscrollble;

}

publicvoidsetScrollble(booleanscrollble) {

this.scrollble = scrollble;

}

}

```

setObjectForPosition()方法中是为了调用存放你的view和他对应的position,这个是参考了鸿洋大神的一篇文章

setObjectForPosition()这个方法了,请看我的一个fragment

```

private CustomViewpager vp;

private int index;

publicSecurityInfoFragment(CustomViewpager vp,int index) {

this.vp = vp;

}

@Nullable

@Override

publicView onCreateView(LayoutInflater inflater,@NullableViewGroup container,@NullableBundle savedInstanceState) {

View view = inflater.inflate(R.layout.xxxxx,null);

vp.setObjectForPosition(view,index);

return view;

}

```

最后一步,就是调用resetheight()方法了,请look代码

```

activityScdetailsBottomVp.setOnPageChangeListener(newViewPager.OnPageChangeListener() {

@Override

publicvoidonPageScrolled(intposition,floatpositionOffset,intpositionOffsetPixels) {

}

@Override

publicvoidonPageSelected(intposition) {

activityScdetailsBottomVp.resetHeight(position);//这句很重要

}

@Override

publicvoidonPageScrollStateChanged(intstate) {

}

});

activityScdetailsBottomVp.resetHeight(0);//这句更重要

}

```

最后,特别声明,本编参考了大神们的博客:

参考了鸿洋大神的一篇文章:http://blog.csdn.net/lmj623565791/article/details/38026503

你可能感兴趣的:(ViewPager +fragment+listview 高度适配,出现大部分空白的问题)