当手指触摸到屏幕时,系统就会调用相应 View 的 onTouchEvent,并传入一系列的 ACTION 。当有多个层级的 View 时,在父层级允许的情况下,这个 ACTION 会一直向下传递直到遇到最深层的 View 。所以 Touch 事件最先调用的是最底层 View 的 onTouchEent,如果 View 的 onTouchEvent 接收到某个 Touch ACTION 并作了相应处理,最后有两种返回方式: true 和 false。return true 会告诉系统当前的 View 需要处理这次的 Touch 事件,以后的系统发出的ACTION_MOVE,ACTION_UP 还是需要继续监听并接收的,而且这次的ACTION 已经被处理掉了,父层的 View 是不可能触发 onTouchEvent 了。所以每一个ACTION 最多只能有一个 onTouchEvent 接口返回true。如果 return false,便会通知系统,当前 View 不关心这一次的 Touch 事件,此时这个 ACTION 会传向父级,调用父级 View 的 onTouchEvent。但是这一次的 Touch 事件之后发出的任何 ACTION ,该 View 都不会再接受,onTouchEvent 在这一次的touch事件中再也不会触发,即一旦某个View返回 false,那么之后的ACTION_MOVE,ACTION_UP 等 ACTION 就不会再传入这个 View,但是下一次 Touch 事件的 ACTION 还是会传进来的。
前面说了底层的 View 能够接收到这次的事件有一个前提条件:在父层级允许的情况下。假设不改变父层级的 dispatch 方法,在系统调用底层 onTouchEvent 之前会先调用 父 View 的 onInterceptTouchEvent 方法判断,父层 View 是不是要截获本次 Touch 事件之后的 ACTION 。如果 onInterceptTouchEvent 返回true,那么本次 Touch 事件之后的所有 ACTION 都不会再向深层的 View 传递,统统都会传给父层 View 的 onTouchEvent,即父层已经截获了这次 Touch 事件,之后的ACTION 也不必询问 onInterceptTouchEvent,在这次的 Touch 事件之后发出的ACTION 时 onInterceptTouchEvent 不会再次调用,直到下一次 Touch 事件的来临。如果 onInterceptTouchEvent 返回false,那么本次 ACTION 将发送给更深层的View,并且之后的每一次 ACTION 都会询问父层的 onInterceptTouchEvent需不需要截获本次 Touch 事件。只有 ViewGroup 才有 onInterceptTouchEvent 方法,因为一个普通的View肯定是位于最深层的View,Touch 事件能够传到这里已经是最后一站了,肯定会调用View的onTouchEvent。
对于底层View来说,调用 getParent().requestDisallowInterceptTouchEvent(true);
方法,可以阻止父View 截获 Touch 事件。一旦底层 View 收到 Touch 的 ACTION 后调用这个方法那么父层 View 就不会再调用onInterceptTouchEvent 了,也无法截获以后的 ACTION 。
用例子总结一下 onInterceptTouchEvent 和 onTouchEvent 的调用顺序:
假设最顶层 View 叫 OuterLayout,中间层 View叫InnerLayout,最底层 View 叫 MyVIew 。调用顺序是这样的(假设各个函数返回的都是 false)
OuterLayout.onInterceptTouchEvent->InnerLayout.onInterceptTouchEvent -> MyView.onTouchEvent -> InnerLayout.onTouchEvent->OuterLayout.onTouchEvent。
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
getParent().requestDisallowInterceptTouchEvent(true);
return super.dispatchTouchEvent(ev);
}
这句话的意思是告诉父view,我的事件我自己处理。
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
pager.requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
pager.requestDisallowInterceptTouchEvent(false);
break;
}
}
也可以写成类似于上面那样,当用户按下的时候,我们告诉父组件,不要拦截我的事件(这个时候子组件是可以正常响应事件的),拿起之后就会告诉父组件可以阻止。当ScrollView中嵌套ListView产生冲突时,就可以用这种方法解决。
参考:http://blog.csdn.net/chaihuasong/article/details/17499799