HorizontalScrollView 和 ViewPager 触控冲突解决

前言

当 HorizontalScrollView 和 ViewPager 一起使用的时候会出现滑动冲突的问题

解决过程

要了解 HorizontalScrollView 和 ViewPager 触控冲突的原因,首先需要了解Android 触摸事件处理的的机制,在了解后可以知道,当 HorizontalScrollView 内层嵌套使用 ViewPager 时,由于触摸事件被 HorizontalScrollView 的 onInterceptTouchEvent() 拦截导致事件不能向下层传递,所以当滑动屏幕时,HorizontalScrollView 可以正常滑动,但是 ViewPager 却不能正常滑动,而这个时候我们期望的是边缘滑动时,HorizontalScrollView 响应事件,非边缘滑动时,ViewPager 响应事件,为了达到这一目的我们需要重写 HorizontalScrollView 的 onInterceptTouchEvent() 函数,具体代码如下:

1
2
3
4
5
6
7
public boolean onInterceptTouchEvent(MotionEvent ev) {
mXPoint = ev.getRawX();
if (mXPoint > 100 && mXPoint < mMenuWidth) {
return false;
}
return super.onInterceptTouchEvent(ev);
}

通过限定滑动的屏幕范围决定是否事件在这一层被处理,在这样处理之后 HorizontalScrollView 和 ViewPager 都能正确响应了,但是当 HorizontalScrollView 滑动至终点时,屏幕中间的部分却不能够正确响应 HorizontalScrollView 的滑动事件,所以我们需要做进一步处理,判断 HorizontalScrollView 是否滑动至终点,所以在 onTouchEvent 事件中利用一个 flag 的标志位去判断是否滑动至终点,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_UP:
int scollX = getScrollX();
if (scollX > mMenuHaltWidth) {  
this.scrollTo(mMenuWidth, 0);
sMenuFlag = false;
} else {
this.scrollTo(0, 0);
sMenuFlag = true;
}
return true;
}
return super.onTouchEvent(ev);
}
 onInterceptTouchEvent() 函数判断条件变为:
 if (mXPoint > 100 && mXPoint < mMenuWidth && sMenuFlag == false)

最终效果


参考资料

  1. Android 控件的触摸事件传递与处理
  2. Android 触摸事件处理机制