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

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

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


当前回答

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

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

其他回答

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

关于这些方法有很多困惑,但实际上并没有那么复杂。大部分的困惑是因为:

如果你的View/ViewGroup或它的任何子视图在中没有返回true onTouchEvent, dispatchTouchEvent和onInterceptTouchEvent将ONLY 为MotionEvent.ACTION_DOWN调用。没有真正的 onTouchEvent,父视图会假设你的视图不需要 MotionEvents。 当一个ViewGroup的子类在onTouchEvent中都没有返回true时,onInterceptTouchEvent只会在MotionEvent中被调用。ACTION_DOWN,即使你的ViewGroup在onTouchEvent中返回true。

处理顺序如下:

dispatchTouchEvent被调用。 onInterceptTouchEvent为MotionEvent调用。ACTION_DOWN或when ViewGroup的任何子对象在onTouchEvent中返回true。 onTouchEvent首先在ViewGroup和的子对象上被调用 当没有子函数返回true时,调用 视图/ ViewGroup。

如果你想预览TouchEvents/MotionEvents而不禁用子类上的事件,你必须做两件事:

重写dispatchTouchEvent以预览事件并返回 super.dispatchTouchEvent (ev); 重写onTouchEvent并返回true,否则你不会得到任何 除了MotionEvent. action_down。

如果你想检测一些手势,如滑动事件,而不禁用其他事件在你的孩子只要你没有检测到的手势,你可以这样做:

预览如上所述的MotionEvents,并设置一个标志 发现了你的手势。 当你的标志被设置为取消时,在onInterceptTouchEvent中返回true 你的孩子的动作事件处理。这也是一种方便 重置标志的位置,因为onInterceptTouchEvent不会被重置 再次调用,直到下一次MotionEvent.ACTION_DOWN。

在framamelayout中覆盖的例子(我的例子是c#,因为我用Xamarin Android编程,但在Java中逻辑是相同的):

public override bool DispatchTouchEvent(MotionEvent e)
{
    // Preview the touch event to detect a swipe:
    switch (e.ActionMasked)
    {
        case MotionEventActions.Down:
            _processingSwipe = false;
            _touchStartPosition = e.RawX;
            break;
        case MotionEventActions.Move:
            if (!_processingSwipe)
            {
                float move = e.RawX - _touchStartPosition;
                if (move >= _swipeSize)
                {
                    _processingSwipe = true;
                    _cancelChildren = true;
                    ProcessSwipe();
                }
            }
            break;
    }
    return base.DispatchTouchEvent(e);
}

public override bool OnTouchEvent(MotionEvent e)
{
    // To make sure to receive touch events, tell parent we are handling them:
    return true;
}

public override bool OnInterceptTouchEvent(MotionEvent e)
{
    // Cancel all children when processing a swipe:
    if (_cancelChildren)
    {
        // Reset cancel flag here, as OnInterceptTouchEvent won't be called until the next MotionEventActions.Down:
        _cancelChildren = false;
        return true;
    }
    return false;
}

ViewGroup子类中的以下代码将阻止它的父容器接收触摸事件:

  @Override
  public boolean dispatchTouchEvent(MotionEvent ev) {
    // Normal event dispatch to this container's children, ignore the return value
    super.dispatchTouchEvent(ev);

    // Always consume the event so it is not dispatched further up the chain
    return true;
  }

我使用自定义覆盖来防止背景视图响应触摸事件。

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

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

答:小

onInterceptTouchEvent出现在setOnTouchListener之前。