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

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

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


当前回答

你可以在这个视频https://www.youtube.com/watch?v=SYoN-OvdZ3M&list=PLonJJ3BVjZW6CtAMbJz1XD8ELUs1KXaTD&index=19和接下来的三个视频中找到答案。所有的触摸事件都解释得很好,它非常清楚,充满了例子。

其他回答

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

简单回答: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将意味着视图不会从该事件接收更多的操作。

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

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

揭开这一神秘面纱的最佳地点是源代码。医生们对这一点解释得很不充分。

dispatchTouchEvent实际上定义在Activity, View和ViewGroup上。可以把它看作一个控制器,它决定如何路由触摸事件。

例如,最简单的情况是视图。dispatchTouchEvent将触摸事件路由到OnTouchListener。onTouch(如果它是定义的)或者扩展方法onTouchEvent。

ViewGroup。dispatchTouchEvent的事情要复杂得多。它需要找出它的哪个子视图应该获得事件(通过调用child. dispatchtouchevent)。这基本上是一个命中测试算法,其中你计算出哪个子视图的边界矩形包含触点坐标。

But before it can dispatch the event to the appropriate child view, the parent can spy and/or intercept the event all together. This is what onInterceptTouchEvent is there for. So it calls this method first before doing the hit testing and if the event was hijacked (by returning true from onInterceptTouchEvent) it sends a ACTION_CANCEL to the child views so they can abandon their touch event processing (from previous touch events) and from then onwards all touch events at the parent level are dispatched to onTouchListener.onTouch (if defined) or onTouchEvent(). Also in that case, onInterceptTouchEvent is never called again.

你甚至想要覆盖[活动|ViewGroup|View].dispatchTouchEvent?除非您正在进行一些自定义路由,否则您可能不应该这样做。

主要的扩展方法是ViewGroup。onInterceptTouchEvent(如果你想监视和/或拦截父级的触摸事件)和View. ontouchlistener /View。onTouchEvent用于主事件处理。

总的来说,在我看来,它的设计过于复杂,但android api更倾向于灵活性而不是简单性。

你可以在这个视频https://www.youtube.com/watch?v=SYoN-OvdZ3M&list=PLonJJ3BVjZW6CtAMbJz1XD8ELUs1KXaTD&index=19和接下来的三个视频中找到答案。所有的触摸事件都解释得很好,它非常清楚,充满了例子。