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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • 这是谷歌官方给我们提供的一个兼容低版本安卓设备的软件包,里面包囊了只有在安卓3.0以上可以使用的api。而view...
    Ten_Minutes阅读 5,733评论 1 19
  • viewpager是用在滚动中相对比较多的,最近做一个定时滚动显示viewpager内容。 步骤: 一:在布局文件...
    jiangbin1992阅读 1,075评论 0 2
  • 首先描述下需求: 1、新增短信时,进来收件人是为空,显示一行文字(提醒) 2、从通讯录选择联系人后,回到短信编辑界...
    小学生写代码阅读 622评论 0 0
  • Android开发艺术探索笔记 SpecMode UNSPECIFIED,表示一种测量状态,对View的大小不做限...
    YangGui阅读 672评论 0 3
  • 一开始让你不舒服的地方千万不要忍,最后让你们分开的,肯定是因为当初那些不愿意。
    空的了阅读 165评论 0 0