高度动态适应的viewpager,高度随子view高度变化

概要

需求:viewpager左右滑动后需加载信息(转圈loading),loading时viewpager的高度要求与之前的页面高度相同。在loading结束后根据页面内容重新自适应viewpager的高度。

前言:在网上找了些viewpager自适应的实现方案,清一色都是在onMeasure中测量所有子view的高度并将最高的高度作为viewpager的高度。此方案的缺点在于从较高的view切换到较矮的view,viewpager填充完子view后底部还有大片空白。故不能满足我的需求。

思路
1.重写viewpager的onMeasure方法,测量当前页面子view的高度,用此高度作为viewpager的高度并记录此高度的值。
2。监听viewpager当前所选页面(onPageSelected)。在页面被选择后显示loading view,并将loading view的高度设置为此前viewpager的高度。
3.loading结束后刷新viewpager的页面,重新触发onMeasure,自适应子view的高度作为viewpager的高度。

重点如何测量当前页面子view的高度?
1.在adapter instantiateItem()拿到当前页的view后,设置该view的id或tag。由于我讲view的tag用于在adapter中复用view,所以在此用id作为当前页的标识。
2.在viewpager的onMeasure()即可通过viewpager当前所选页postion,获取到当前所选页的子view。

遇到的坑

viewpager所在的fragment在两个地方被使用,1在父fragment add此fragment,父布局为RelativeLayout。2在activity中add此fragment,父布局为Framelayout。
坑:发现在2的情况下viewpager无法自适应高度
解决:将2情况的父布局改为RelativeLayout即可。
简要分析:在调试过程中发现2情况下viewpager中的子view高度动态改变后(添加/删除子子view)后,没有重新更新viewpager的高度(onMeasure未被调用)。具体原名不明,请大佬们指教。

Viewpager代码
public class ViewPagerUnderScrollView extends ViewPager implements NestedScrollingChild {

    private int currentHeight = 0;

    public ViewPagerUnderScrollView(@NonNull Context context) {
        super(context);
        initPagerListener();
    }

    private void initPagerListener() {
        addOnPageChangeListener(new OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                RemoteSettingNvrViewPagerAdapter adapter = (RemoteSettingNvrViewPagerAdapter) getAdapter();
                if (null != adapter)
                    adapter.setCurrentHeight(currentHeight);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int height = 0;
        // 在adapter刷新view时,将view的id设置成viewpager当前的页面索引,方便此处找到viewpager当前页的子view。
        View child = findViewById(getCurrentItem());
        if (null != child) {
            child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
            height = child.getMeasuredHeight();
            Log.d(TAG, "onMeasure: height = " + height);
        }
        currentHeight = height;
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

PagerAdapter代码
public class RemoteSettingNvrViewPagerAdapter extends PagerAdapter {
    private int mCurrentHeight;

    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
   		//设置view的id为当前page的索引,以便viewpager onMeasure时可以获取到当前的view。
   		convertView.setId(position);
   		//更新view
        holder.notifyData(bean, mCurrentHeight);
        return convertView;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值