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

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

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


当前回答

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;
  }

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

其他回答

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

如果你的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的dispatchTouchEvent()方法使用onInterceptTouchEvent()来选择是否应该立即处理触摸事件(使用onTouchEvent())或继续通知其子方法的dispatchTouchEvent()。

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

答:小

onInterceptTouchEvent出现在setOnTouchListener之前。

主要区别:

•Activity. dispatchtouchevent (MotionEvent) -这允许您的Activity 来拦截所有的触摸事件,然后再将它们分派到 窗口。 •ViewGroup.onInterceptTouchEvent(MotionEvent) -这允许一个 ViewGroup来监视事件,因为它们被分派到子视图。