概要
需求: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;
}
}