高度自适应的ViewPager--SelfAdaptingViewPager

来源:互联网 发布:数据采集流程图 编辑:程序博客网 时间:2024/05/17 23:41

       之前项目遇到了一个需求,需要scrollview里面嵌套一个viewpager,而且要做到切换viewpager的时候恰好完全展示对应的page。

       在网上搜索了很久,只看到某位大神提供的CustomViewPager,代码如下:  

public class CustomViewPager extends ViewPager {             public CustomViewPager(Context context) {            super(context);        }             public CustomViewPager(Context context, AttributeSet attrs) {            super(context, attrs);        }             @Override        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {                 int height = 0;            for (int i = 0; i < getChildCount(); i++) {                View child = getChildAt(i);                child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));                int h = child.getMeasuredHeight();                if (h > height)                    height = h;            }                 heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);                 super.onMeasure(widthMeasureSpec, heightMeasureSpec);        }    }

      研究一番后发现,onMeasure方法中最后记录的是所有page多次测量后高度中的最大值,这样两个高度不一的page虽然都能完全展示,但是高度矮的那个就会有留白,不符合我们恰好展示的需求。

      于是我对代码进行了修改,有了SelfAdaptingViewPager,代码如下:  

public class SelfAdaptingViewPager extends ViewPager {    private Map<Integer, Integer> map             = new HashMap<>(2);    private int                   currentPosition = 0;    private MarginLayoutParams params;    public SelfAdaptingViewPager(Context context) {        super(context);    }    public SelfAdaptingViewPager(Context context, AttributeSet attrs) {        super(context, attrs);    }    //在View的绘制过程中此方法会被多次调用,每次都会测量出新的数据,我们用最新的数据替换旧的数据      @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        for (int i = 0; i < getChildCount(); i++) {            View child = getChildAt(i);            child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));            int h = child.getMeasuredHeight();            Log.d("SelfAdaptingViewPager", "measuredHeight=" + h);            Log.d("SelfAdaptingViewPager", "getChildCount=" + getChildCount());            Log.d("SelfAdaptingViewPager", "getChildAt(i)=" + i);             /* Log.d("SelfAdaptingViewPager", "getChildAt(i).getId())=" + getChildAt(i).getId());             if (Build.VERSION.SDK_INT > 19) {                 map.put(Math.abs(i - 1), h);             } else {*/            map.put(i, h);            //            }          }        int height = 0;        //onMeasure第一次被调用的时候,遍历不到child(View的绘制流程只是了解最基本的,我就不解释了)          height = map.get(currentPosition) == null ? 0 : map.get(currentPosition);        Log.d("SelfAdaptingViewPager", "height=" + height);        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);        super.onMeasure(widthMeasureSpec, heightMeasureSpec);    }    //在切换tab的时候,重置ViewPager的高度      public void resetHeight(int currentPosition) {        this.currentPosition = currentPosition;        params = (MarginLayoutParams) getLayoutParams();        if (params == null) {            params = new MarginLayoutParams(LayoutParams.MATCH_PARENT, map.get(currentPosition));        } else {            params.height = map.get(currentPosition);        }        setLayoutParams(params);    }}

            但是我在用android4.4的机型测试时发现了问题,一个page留白,一个page不能完全展示,显然两个page所展示的高度正好弄反了。

       后来发现是和手机的android版本有关,使用android版本4.4及以下的机型都有这个问题。遍历viewpager的儿子,得到的第一个儿子是第二个page对应的view,得到的第二儿子是第一个page对应的view。

      这次周末在家我想再研究一下这个问题,结果自己写的demo在任何机型上并不会出现这样的问题。

      最终发现问题的出现和依赖的v7包有关系,我在工作项目中依赖的是com.android.support:appcompat-v7:23.4.0,demo中依赖的是com.android.support:appcompat-v7:23.1.1,所以可能是不同版本的v7包所包含的v4包中ViewPager对于getChildAt的实现有区别吧,以后有时间和基础了我想我会进一步研究的。

      下面是demo的截图:

      

      demo的代码地址:https://github.com/tingshuonitiao/AndroidStudy
0 0