您的位置:首页 > 其它

解决ViewPager与GridView嵌套的滑动不流畅和高度无法自适应

2017-01-04 16:04 447 查看
最近产品提了一个需求,要求把首页的导航按钮改成和美团类似的可翻页的GridView。


乍一看,这不就是ViewPager嵌套两个GridView吗,简单简单。简单的答应后,我就掉进了控件嵌套的大坑中。

简单的写好代码后,满心欢喜的运行程序,咦???我的ViewPager去哪了?GridView呢?(黑人问号)在一番努力之后,我终于找到了问题的原因,当Viewpager和GridView嵌套时,如果ViewPager的高度设置成warp_content,会导致控件不显示。解决这个问题有两个方案。

一、既然warp_content不行,那么给ViewPager直接设置一个高度!搞定,简单省事,不过这样有一个缺点,就是没法保证所有机型适配,而且有时候GridView内容多,有两行并分页,有时候内容少,只有一行,那么就会空出一部分的高度,导致界面不美观。

二、上面的方法有点太简单粗暴了,这里就介绍一下我现在用的方法,自定义一个ViewPager,在onMeasure中计算他的子View的高度,取最高的来作为自己的高度。代码如下

/**
* 根据测量的子view设置pager高度
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@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);
}


当然,用了方法二之后,如果你用的是普通的GridView和我们自定义的ViewPager嵌套的话,会发现一个事情,那就是我们的GridView的第二行不见了!只剩下了一行,又是嵌套的鬼问题,GridView显示不全了,这里我们的GridView也需要自定义一下,这个就比较普遍了,大家一般都是用的这个,重写一下GridView的onMeasure。

public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}


好了!大功告成!我们的ViewPager可以和GridView嵌套并且能自适应高度啦!开心的赶紧上去滑一滑,可是一碰,感觉有点不对劲。滑动的时候总感觉没那么灵敏,很难滑到第二页,这也是因为控件嵌套导致手势冲突。没关系,我们接着回到我们自定义的ViewPager中,重写他的dispachTouchEvent方法

private float mPointX;
private float mPointY;
/**
* 解决嵌套后滑动不灵敏问题
* @param ev
* @return
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mPointX = ev.getX();
mPointY = ev.getY();
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
if (Math.abs(ev.getX() - mPointX) > Math.abs(ev.getY() - mPointY)) {
getParent().requestDisallowInterceptTouchEvent(true);
} else {
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
getParent().requestDisallowInterceptTouchEvent(false);
break;

default:
break;
}
return super.dispatchTouchEvent(ev);

}


记录一下手指按下时的X,Y坐标,然后在移动通过计算,如果左右移动的话就阻止父控件拦截事件,这样就能在左右滑动的时候灵活滑动了。

好了,这个问题解决以后,我们的控件应该就比较完整了,其他都是GridView和ViewPager的老套路。终于跳出了GridView和ViewPager嵌套的大坑,希望能够帮助到有同样需求的同学。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐