Android中onInterceptTouchEvent和dispatchTouchEvent的区别是什么?

根据android开发者指南,这两种方法都可以用来拦截触摸事件(MotionEvent),但有什么区别呢?

onInterceptTouchEvent, dispatchTouchEvent和onTouchEvent如何在视图(ViewGroup)的层次结构中一起交互?


当前回答

补充回答

以下是对其他答案的视觉补充。我的完整答案在这里。

ViewGroup的dispatchTouchEvent()方法使用onInterceptTouchEvent()来选择是否应该立即处理触摸事件(使用onTouchEvent())或继续通知其子方法的dispatchTouchEvent()。

其他回答

Activity和View都有dispatchTouchEvent()和onTouchEvent方法。ViewGroup也有这个方法,但是有另一个叫做onInterceptTouchEvent的方法。这些方法的返回类型是布尔型,您可以通过返回值控制调度路由。

Android中的事件调度从Activity->ViewGroup->View开始。

简单回答:dispatchTouchEvent()将首先被调用。

简短的建议:不应该重写dispatchTouchEvent(),因为它很难控制,有时它会降低您的性能。恕我直言,我建议重写onInterceptTouchEvent()。


因为大多数答案都非常清楚地提到了活动/视图组/视图上的流触摸事件,我只添加了更多关于ViewGroup中这些方法的代码细节(忽略dispatchTouchEvent()):

onInterceptTouchEvent()将首先被调用,ACTION事件将分别被调用down -> move -> up。有2种情况:

If you return false in 3 cases (ACTION_DOWN, ACTION_MOVE, ACTION_UP), it will consider as the parent won't need this touch event, so onTouch() of the parents never calls, but onTouch() of the children will call instead; however please notice: The onInterceptTouchEvent() still continue to receive touch event, as long as its children don't call requestDisallowInterceptTouchEvent(true). If there are no children receiving that event (it can happen in 2 cases: no children at the position the users touch, or there are children but it returns false at ACTION_DOWN), the parents will send that event back to onTouch() of the parents. Vice versa, if you return true, the parent will steal this touch event immediately, and onInterceptTouchEvent() will stop immediately, instead onTouch() of the parents will be called as well as all onTouch() of children will receive the last action event - ACTION_CANCEL (thus, it means the parents stole touch event, and children cannot handle it from then on). The flow of onInterceptTouchEvent() return false is normal, but there is a little confusion with return true case, so I list it here: Return true at ACTION_DOWN, onTouch() of the parents will receive ACTION_DOWN again and following actions (ACTION_MOVE, ACTION_UP). Return true at ACTION_MOVE, onTouch() of the parents will receive next ACTION_MOVE (not the same ACTION_MOVE in onInterceptTouchEvent()) and following actions (ACTION_MOVE, ACTION_UP). Return true at ACTION_UP, onTouch() of the parents will NOT called at all since it's too late for the parents to steal touch event.

还有一件重要的事情是onTouch()中事件的ACTION_DOWN将决定视图是否希望从该事件接收更多的动作。如果视图在onTouch()中的ACTION_DOWN处返回true,这意味着视图愿意从该事件接收更多操作。否则,在onTouch()中的ACTION_DOWN处返回false将意味着视图不会从该事件接收更多的操作。

ViewGroup的onInterceptTouchEvent()总是ACTION_DOWN事件的入口点,这是第一个发生的事件。

如果你想让ViewGroup处理这个手势,从onInterceptTouchEvent()返回true。 在返回true时,ViewGroup的onTouchEvent()将接收到下一次ACTION_UP或ACTION_CANCEL之前的所有后续事件,在大多数情况下,ACTION_DOWN和ACTION_UP或ACTION_CANCEL之间的触摸事件为ACTION_MOVE,通常会被识别为滚动/抛动手势。

如果你从onInterceptTouchEvent()返回false,目标视图的onTouchEvent()将被调用。它将被重复用于后续的消息,直到你从onInterceptTouchEvent()返回true。

来源: http://neevek.net/posts/2013/10/13/implementing-onInterceptTouchEvent-and-onTouchEvent-for-ViewGroup.html

public boolean dispatchTouchEvent(MotionEvent ev){
    boolean consume =false;
    if(onInterceptTouchEvent(ev){
        consume = onTouchEvent(ev);
    }else{
        consume = child.dispatchTouchEvent(ev);
    }
}

答:小

onInterceptTouchEvent出现在setOnTouchListener之前。