在实际项目需求中,经常会遇到ScrollView嵌套纵向可滚动的View,比如ListView,TextView。在默认情况下,ScrollView检测到纵向有滚动就会intercept touch事件然后滚动自身,导致子View根本无法滚动。
网友的大部分做法是在子View检测到Down事件时马上requestDisallowInterceptTouchEvent,检测到Up事件时再取消request。实际效果存在一个问题,如果子View本身内容比较少,根本不需要滚动,此时会发现手指在上面滚动时没有效果。
下面的示例稍作改动,仅在子View可滚动的情况下才请求parent不要拦截事件,在滚动完毕后告诉parent可以拦截事件。
同样是复写子View的OnTouchEvent,当然调用子View的setOnTouchListener也是一样的
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// do nothing
break;
case MotionEvent.ACTION_MOVE:
int deltaY = (int) (event.getY() - lastY);
if (deltaY > 0) { // pull down currently
// if view support pull down, then request parent do not intercept touch event.
getParent().requestDisallowInterceptTouchEvent(canScrollVertically(-1));
} else if (deltaY < 0) { // pull up currently
getParent().requestDisallowInterceptTouchEvent(canScrollVertically(1));
}
break;
case MotionEvent.ACTION_UP:
// reset state
getParent().requestDisallowInterceptTouchEvent(false);
break;
case MotionEvent.ACTION_CANCEL:
// parent has intercepted the touch event
break;
}
lastY = event.getY();
// call super to process scrolling
return super.onTouchEvent(event);
}
外面只需要根据deltaY计算出用户滑动方向,然后判断该方向上是否可以滑动,是则告诉parent不要拦截事件,否则告诉parent可以拦截。