布局层级为NestedScrollView-ViewPager-Fragment-RecyclerView的布局,切换ViewPager中的内容时,部分页面底部出现空白
我们的app首页中有一个模块的布局层级为NestedScrollView-ViewPager-Fragment-RecyclerView,每一页以列表的形式显示数据。由于有的页面列表数据多,有的页面数据少,每个页面的数据长度不一致,数据少的页面会出现空白页面。这是不同的RecyclerView的外层是同一个ViewPager,数据长的页面将ViewPager撑长了导致的。
对于这个问题的解题思路主要分两步。
一、自定义ViewPager,内部会有一个列表HashMap<Integer, View> mChildrenViews,用于缓存加入的View,在构建相应的fragment的时候,将 viewPager对象和当前fragment的位置mPosition传入fragment中;然后在fragment的onCreateView中调用mViewPager.setObjectForPosition(rootView, mPosition)缓存view;
二、每次切换的时候,通过ViewTreeObserver.OnGlobalLayoutListener获取到当前RecyclerView的高度,然后动态的修改ViewPager的高度,在setUserVisibleHint方法中添加OnGlobalLayoutListener监听
下面是主要代码
public class AutofitHeightViewPager extends ViewPager {
private int current;
private int height = 0;
/**
* 保存position与对于的View
*/
private HashMap<Integer, View> mChildrenViews = new LinkedHashMap<Integer, View>();
private boolean scrollble = true;
public AutofitHeightViewPager(Context context) {
super(context);
}
public AutofitHeightViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mChildrenViews.size()!=0&&mChildrenViews.containsKey(current)) {
View child = mChildrenViews.get(current);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
height = child.getMeasuredHeight();
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void resetHeight(int current,int height) {
this.current = current;
if (mChildrenViews.size()>=current) {
ViewGroup.LayoutParams layoutParams = (ViewGroup.LayoutParams) getLayoutParams();
if (layoutParams == null) {
layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height);
} else {
layoutParams.height = height;
}
setLayoutParams(layoutParams);
}
}
/**
* 保存position与对于的View
*/
public void setObjectForPosition(View view, int position)
{
mChildrenViews.put(position, view);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (!scrollble) {
return true;
}
return super.onTouchEvent(ev);
}
}
private ViewTreeObserver.OnGlobalLayoutListener mOnGlobalLayoutListener= new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//传入 RecyclerView 高度,并做一些 Adapter 的初始化工作
if (rcList != null){
int height = rcList.getHeight();
if (height != 0 && lastHeight != height){
lastHeight =height;
Logger.d("height:"+height);
rcList.getViewTreeObserver().removeOnGlobalLayoutListener(mOnGlobalLayoutListener);
mViewPager.resetHeight(mPosition, height);
}
}
}
};
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser){
if (lastHeight != 0){
mViewPager.resetHeight(mPosition,lastHeight);
}else {
if (rcList != null){
rcList.getViewTreeObserver().addOnGlobalLayoutListener(mOnGlobalLayoutListener);
}
}
}else {
if (rcList != null){
rcList.getViewTreeObserver().removeOnGlobalLayoutListener(mOnGlobalLayoutListener);
}
}
}