scrollview中嵌套viewpager不显示

 

      没有时间弄一幅动图,那我就口述一下吧,很多Android开发者会遇到的问题,例如,你的整个布局在一个线性布局(Linearlayout)中,简单的(vertical)竖行排列,你的viewpager上面有一些其他布局,viewpager在最下面,所以很可能嵌套在scrollview中,为了解决viewpager和scorllview的冲突,你很可能去百度viewpager的高度自适应,结果如图:

[java] view plain copy

  1. /** 
  2.  * 自动适应高度的ViewPager 
  3.  * @author  
  4.  * 
  5.  */  
  6. public class CustomViewPager extends ViewPager {  
  7.    
  8.     public CustomViewPager(Context context) {  
  9.         super(context);  
  10.     }  
  11.    
  12.     public CustomViewPager(Context context, AttributeSet attrs) {  
  13.         super(context, attrs);  
  14.     }  
  15.    
  16.     @Override  
  17.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  18.    
  19.         int height = 0;  
  20.         for (int i = 0; i < getChildCount(); i++) {  
  21.             View child = getChildAt(i);  
  22.             child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));  
  23.             int h = child.getMeasuredHeight();  
  24.             if (h > height)  
  25.                 height = h;  
  26.         }  
  27.    
  28.         heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);  
  29.    
  30.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  31.     }  
  32. }  

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

   

 我们就拿viewpager+fragment,最常见的scrollview嵌套viewpager的例子,首先看我自定义的viewpager

[java] view plain copy

  1. package com.xxx.xxx.views;  
  2.   
  3. import android.content.Context;  
  4. import android.support.v4.app.Fragment;  
  5. import android.support.v4.view.ViewPager;  
  6. import android.util.AttributeSet;  
  7. import android.util.TypedValue;  
  8. import android.view.MotionEvent;  
  9. import android.view.View;  
  10. import android.widget.LinearLayout;  
  11.   
  12. import java.util.HashMap;  
  13. import java.util.Map;  
  14.   
  15. /** 
  16.  * Created by vipui on 16/8/25. 
  17.  */  
  18.   
  19. public class CustomViewpager extends ViewPager {  
  20.     private int current;  
  21.     private int height = 0;  
  22.   
  23.     private boolean scrollble = true;  
  24.   
  25.     public CustomViewpager(Context context) {  
  26.         super(context);  
  27.     }  
  28.   
  29.     public CustomViewpager(Context context, AttributeSet attrs) {  
  30.         super(context, attrs);  
  31.     }  
  32.   
  33.     @Override  
  34.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  35.   
  36.   
  37.         if (getChildCount() > current) {  
  38.             View child = getChildAt(current);  
  39.             child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));  
  40.             int h = child.getMeasuredHeight();  
  41.             height = h;  
  42.         }  
  43.   
  44.         heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);  
  45.   
  46.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  47.     }  
  48.   
  49.     public voidresetHeight(int current) {  
  50.         this.current = current;  
  51.         if (getChildCount() > current) {  
  52.             LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();  
  53.             if (layoutParams == null) {  
  54.                 layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, height);  
  55.             } else {  
  56.                 layoutParams.height = height;  
  57.             }  
  58.             setLayoutParams(layoutParams);  
  59.         }  
  60.     }  
  61.   
  62.   
  63.     @Override  
  64.     public boolean onTouchEvent(MotionEvent ev) {  
  65.         if (!scrollble) {  
  66.             return true;  
  67.         }  
  68.         return super.onTouchEvent(ev);  
  69.     }  
  70.   
  71.   
  72.     public boolean isScrollble() {  
  73.         return scrollble;  
  74.     }  
  75.   
  76.     public void setScrollble(boolean scrollble) {  
  77.         this.scrollble = scrollble;  
  78.     }  
  79.   
  80.   
  81. }  

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

[java] view plain copy

  1. activityScdetailsBottomVp.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {  
  2.            @Override  
  3.            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {  
  4.   
  5.            }  
  6.   
  7.            @Override  
  8.            public void onPageSelected(int position) {  
  9.            activityScdetailsBottomVp.resetHeight(position);  
  10.   
  11.                if (position == 0) {  
  12.   
  13.                    activityScdetailsBottomLinear.setBackgroundResource(R.drawable.fishbone_diagram_list_btn_1);  
  14.                    activityScdetailsBottomTaskTv.setTextColor(Color.parseColor("#ffffff"));  
  15.                    activityScdetailsBottomInfoTv.setTextColor(Color.parseColor("#c1c1c1"));  
  16.                    activityScdetailsBottomTimeTv.setTextColor(Color.parseColor("#c1c1c1"));  
  17.   
  18.                } else if (position == 1) {  
  19.   
  20.                    activityScdetailsBottomLinear.setBackgroundResource(R.drawable.fishbone_diagram_list_btn_2);  
  21.                    activityScdetailsBottomTaskTv.setTextColor(Color.parseColor("#c1c1c1"));  
  22.                    activityScdetailsBottomInfoTv.setTextColor(Color.parseColor("#ffffff"));  
  23.                    activityScdetailsBottomTimeTv.setTextColor(Color.parseColor("#c1c1c1"));  
  24.                } else {  
  25.   
  26.                    activityScdetailsBottomLinear.setBackgroundResource(R.drawable.fishbone_diagram_list_btn_3);  
  27.                    activityScdetailsBottomTaskTv.setTextColor(Color.parseColor("#c1c1c1"));  
  28.                    activityScdetailsBottomInfoTv.setTextColor(Color.parseColor("#c1c1c1"));  
  29.                    activityScdetailsBottomTimeTv.setTextColor(Color.parseColor("#ffffff"));  
  30.                }  
  31.            }  
  32.            @Override  
  33.            public void onPageScrollStateChanged(int state) {  
  34.   
  35.            }  
  36.        });  
  37.        activityScdetailsBottomVp.<span style="color:#ff6666;">resetHeight(0)</span>;  
  38.   
  39.   
  40.    }  


在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的高度(预加载到第一个),以此类推。解决这个问题的方法有两个,

 

第一个,看代码(对照上面代码)

[java] view plain copy

  1. activityScdetailsBottomVp.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {  
  2.             @Override  
  3.             public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {  
  4.   
  5.             }  
  6.   
  7.             @Override  
  8.             public void onPageSelected(int position) {  
  9.                 if (position == 0) {  
  10.                    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {  
  11.                         activityScdetailsBottomVp.resetHeight(1);  
  12.                     } else {  
  13.                         activityScdetailsBottomVp.resetHeight(0);  
  14.                     }  
  15.                     activityScdetailsBottomLinear.setBackgroundResource(R.drawable.fishbone_diagram_list_btn_1);  
  16.                     activityScdetailsBottomTaskTv.setTextColor(Color.parseColor("#ffffff"));  
  17.                     activityScdetailsBottomInfoTv.setTextColor(Color.parseColor("#c1c1c1"));  
  18.                     activityScdetailsBottomTimeTv.setTextColor(Color.parseColor("#c1c1c1"));  
  19.                 } else if (position == 1) {  
  20.                     if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {  
  21.                         activityScdetailsBottomVp.resetHeight(2);  
  22.                     } else {  
  23.                         activityScdetailsBottomVp.resetHeight(1);  
  24.                     }  
  25.                     activityScdetailsBottomLinear.setBackgroundResource(R.drawable.fishbone_diagram_list_btn_2);  
  26.                     activityScdetailsBottomTaskTv.setTextColor(Color.parseColor("#c1c1c1"));  
  27.                     activityScdetailsBottomInfoTv.setTextColor(Color.parseColor("#ffffff"));  
  28.                     activityScdetailsBottomTimeTv.setTextColor(Color.parseColor("#c1c1c1"));  
  29.                 } else {  
  30.                     if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {  
  31.                         activityScdetailsBottomVp.resetHeight(0);  
  32.                     } else {  
  33.                         activityScdetailsBottomVp.resetHeight(2);  
  34.                     }  
  35.                     activityScdetailsBottomLinear.setBackgroundResource(R.drawable.fishbone_diagram_list_btn_3);  
  36.                     activityScdetailsBottomTaskTv.setTextColor(Color.parseColor("#c1c1c1"));  
  37.                     activityScdetailsBottomInfoTv.setTextColor(Color.parseColor("#c1c1c1"));  
  38.                     activityScdetailsBottomTimeTv.setTextColor(Color.parseColor("#ffffff"));  
  39.                 }  
  40.             }  
  41.   
  42.             @Override  
  43.             public void onPageScrollStateChanged(int state) {  
  44.   
  45.             }  
  46.   
  47.         });  
  48.         if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {  
  49.             activityScdetailsBottomVp.resetHeight(1);  
  50.         } else {  
  51.             activityScdetailsBottomVp.resetHeight(0);  
  52.         }  
  53.     }  

简单粗暴的办法,用版本控制你要加载的页面高度,亲测可以解决,但是并不知道到了哪个高版本出现了变化,我这里用的是KITKAT(android4.4),这个临界点有待商量。

第二种:(简单粗暴的方法毕竟不合理)所以介绍另一种更加合理的方法。(先看我的自定义viewpager,可以对比一下上面的)

[java] view plain copy

  1. package com.xx.xxxx.views;  
  2.   
  3. import android.content.Context;  
  4. import android.os.Build;  
  5. import android.support.v4.app.Fragment;  
  6. import android.support.v4.view.ViewPager;  
  7. import android.util.AttributeSet;  
  8. import android.util.TypedValue;  
  9. import android.view.MotionEvent;  
  10. import android.view.View;  
  11. import android.widget.LinearLayout;  
  12.   
  13. import java.util.ArrayList;  
  14. import java.util.HashMap;  
  15. import java.util.LinkedHashMap;  
  16. import java.util.List;  
  17. import java.util.Map;  
  18.   
  19. /** 
  20.  * Created by vipui on 16/8/25. 
  21.  */  
  22.   
  23. public class CustomViewpager extends ViewPager {  
  24.     private int current;  
  25.     private int height = 0;  
  26.     /** 
  27.      * 保存position与对于的View 
  28.      */  
  29.     private HashMap<Integer, View> mChildrenViews = new LinkedHashMap<Integer, View>();  
  30.   
  31.     private boolean scrollble = true;  
  32.   
  33.     public CustomViewpager(Context context) {  
  34.         super(context);  
  35.     }  
  36.   
  37.     public CustomViewpager(Context context, AttributeSet attrs) {  
  38.         super(context, attrs);  
  39.     }  
  40.   
  41.   
  42.     @Override  
  43.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  44.         if (mChildrenViews.size() > current) {  
  45.             View child = mChildrenViews.get(current);  
  46.             child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));  
  47.             height = child.getMeasuredHeight();  
  48.         }  
  49.   
  50.         heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);  
  51.   
  52.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  53.     }  
  54.   
  55.     public void resetHeight(int current) {  
  56.         this.current = current;  
  57.         if (mChildrenViews.size() > current) {  
  58.   
  59.             LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();  
  60.             if (layoutParams == null) {  
  61.                 layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, height);  
  62.             } else {  
  63.                 layoutParams.height = height;  
  64.             }  
  65.             setLayoutParams(layoutParams);  
  66.         }  
  67.     }  
  68.     /** 
  69.      * 保存position与对于的View 
  70.      */  
  71.     public void setObjectForPosition(View view, int position)  
  72.     {  
  73.         mChildrenViews.put(position, view);  
  74.     }  
  75.   
  76.   
  77.     @Override  
  78.     public boolean onTouchEvent(MotionEvent ev) {  
  79.         if (!scrollble) {  
  80.             return true;  
  81.         }  
  82.         return super.onTouchEvent(ev);  
  83.     }  
  84.   
  85.   
  86.     public boolean isScrollble() {  
  87.         return scrollble;  
  88.     }  
  89.   
  90.     public void setScrollble(boolean scrollble) {  
  91.         this.scrollble = scrollble;  
  92.     }  
  93.   
  94. }  

[java] view plain copy

  1. setObjectForPosition()方法中是为了调用存放你的view和他对应的position,这个是参考了鸿洋大神的一篇文章,链接:http://blog.csdn.net/lmj623565791/article/details/38026503,为了防止预加载导致的高度不匹配,我们加自身的fragment和position对应起来放在linkedmap里。  
  2. 好了,剩下的就是调用  
  3. setObjectForPosition()这个方法了,请看我的一个fragment  
 
 

[java] view plain copy

  1. public SecurityInfoFragment(CustomViewpager vp) {  
  2.         this.vp = vp;  
  3.     }  
  4.   
  5.   
  6.     @Nullable  
  7.     @Override  
  8.     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {  
  9.         View view = inflater.inflate(R.layout.fg_sc_filght_info, null);  
  10.         ButterKnife.bind(this, view);  
  11.         vp.setObjectForPosition(view,1);  
  12.         return view;  
  13.     }  


 

在你的fragment中将其view放进去。

好了,最后一步,就是调用resetheight()方法了,看代码吧

[java] view plain copy

  1.  activityScdetailsBottomVp.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {  
  2.             @Override  
  3.             public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {  
  4.   
  5.             }  
  6.   
  7.             @Override  
  8.             public void onPageSelected(int position) {  
  9.                 activityScdetailsBottomVp.resetHeight(position);  
  10.   
  11.                 if (position == 0) {  
  12.   
  13.                     activityScdetailsBottomLinear.setBackgroundResource(R.drawable.fishbone_diagram_list_btn_1);  
  14.                     activityScdetailsBottomTaskTv.setTextColor(Color.parseColor("#ffffff"));  
  15.                     activityScdetailsBottomInfoTv.setTextColor(Color.parseColor("#c1c1c1"));  
  16.                     activityScdetailsBottomTimeTv.setTextColor(Color.parseColor("#c1c1c1"));  
  17.   
  18.                 } else if (position == 1) {  
  19. //                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {  
  20. //                        activityScdetailsBottomVp.resetHeight(2);  
  21. //                    } else {  
  22. //                        activityScdetailsBottomVp.resetHeight(1);  
  23. //                    }  
  24.                     activityScdetailsBottomLinear.setBackgroundResource(R.drawable.fishbone_diagram_list_btn_2);  
  25.                     activityScdetailsBottomTaskTv.setTextColor(Color.parseColor("#c1c1c1"));  
  26.                     activityScdetailsBottomInfoTv.setTextColor(Color.parseColor("#ffffff"));  
  27.                     activityScdetailsBottomTimeTv.setTextColor(Color.parseColor("#c1c1c1"));  
  28.                 } else {  
  29.   
  30.                     activityScdetailsBottomLinear.setBackgroundResource(R.drawable.fishbone_diagram_list_btn_3);  
  31.                     activityScdetailsBottomTaskTv.setTextColor(Color.parseColor("#c1c1c1"));  
  32.                     activityScdetailsBottomInfoTv.setTextColor(Color.parseColor("#c1c1c1"));  
  33.                     activityScdetailsBottomTimeTv.setTextColor(Color.parseColor("#ffffff"));  
  34.                 }  
  35.             }  
  36.             @Override  
  37.             public void onPageScrollStateChanged(int state) {  
  38.   
  39.             }  
  40.         });  
  41.         activityScdetailsBottomVp.resetHeight(0);  
  42.   
  43.   
  44.     }  

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值