ViewPager真正做到自适应高度

ViewPager控件,我以前的做法都是直接写死高度,这个对于做广告滚动图的还可以,因为高度都是16:9,写死也没关系。但是对于显示那些动态数据列表,这明显已经不满足需求了。

其他大部分控件的的自适应都是用这个wrap_content属性就可以搞定,但是对于ViewPager来说没有效果,不设置高度就不显示处理,我想到的解决办法就是重写onMeasure方法。

原理是:获取子控件的高度用于重新设置ViewPager的高度

第一种做法是:遍历ViewPager的子控件,获取子控件最大的height值做完ViewPager的高度,不过这种容易导致数据少的View底部有一大块空白,明显不满足友好的用户体验

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

第二种做法是:根据子控件的索引,直接获取当前显示子控件的高度,重设ViewPager的高度。具体代码如下

public class WrapContentHeightViewPager extends ViewPager {

    private int currentIndex;
    private int height = 0;
    //保存view对应的索引
    private HashMap<Integer, View> mChildrenViews = new LinkedHashMap<Integer, View>();


    public WrapContentHeightViewPager(Context context) {
        super(context);
    }

    public WrapContentHeightViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mChildrenViews.size() > currentIndex) {
            View child = mChildrenViews.get(currentIndex);
            child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
            height = child.getMeasuredHeight();
        }
        if (mChildrenViews.size() != 0) {
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    /**
     * 重新设置高度
     *
     * @param current
     */
    public void resetHeight(int current) {
        currentIndex = current;
        if (mChildrenViews.size() > current) {
            LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
            if (layoutParams == null) {
                layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, height);
            } else {
                layoutParams.height = height;
            }
            setLayoutParams(layoutParams);
        }
    }

    /**
     * 保存View对应的索引,需要自适应高度的一定要设置这个
     */
    public void setViewForPosition(View view, int position) {
        mChildrenViews.put(position, view);
    }
}

用法是:实现ViewPager的 滑动监听事件,滑动之后根据当前子控件的索引,传入进去重新设置高度,开始需要一个默认的

private void initViewPagerListener() {
        mViewPagerView.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            }

            @Override
            public void onPageSelected(int position) {
                mViewPagerView.resetHeight(position);
            }

            @Override
            public void onPageScrollStateChanged(int state) {
            }
        });
        mViewPagerView.resetHeight(0);
}

其实上面resetHeight 里面的高度是啥都没所谓,因为执行setLayoutParams 就会触发onMeasure方法,onMeasure方法里面就有获取当前子控件高度,重新设置给ViewPager的处理

特别注意:需要自适应高度的一定要在你的子控件里面,子控件里面,子控件里面设置setViewForPosition

 /**
     * 用于自适应高度
     * @param mViewPagerView
     */
    public void setWrapContentHeightViewPager(WrapContentHeightViewPager mViewPagerView) {
        mViewPagerView.setViewForPosition(this,0);
    }

猜你喜欢

转载自blog.csdn.net/u014476720/article/details/81381728
今日推荐