Android中onInterceptTouchEvent和dispatchTouchEvent的区别是什么?
根据android开发者指南,这两种方法都可以用来拦截触摸事件(MotionEvent),但有什么区别呢?
onInterceptTouchEvent, dispatchTouchEvent和onTouchEvent如何在视图(ViewGroup)的层次结构中一起交互?
Android中onInterceptTouchEvent和dispatchTouchEvent的区别是什么?
根据android开发者指南,这两种方法都可以用来拦截触摸事件(MotionEvent),但有什么区别呢?
onInterceptTouchEvent, dispatchTouchEvent和onTouchEvent如何在视图(ViewGroup)的层次结构中一起交互?
当前回答
因为这是谷歌的第一个结果。我想在Youtube上分享Dave Smith的演讲:精通Android触摸系统,幻灯片可以在这里找到。让我对Android Touch System有了一个很深刻的了解:
Activity如何处理触摸:
Activity.dispatchTouchEvent () 总是第一个被叫到 发送事件到附加到窗口的根视图 onTouchEvent () 如果没有视图使用该事件则调用 总是最后一个被叫
视图如何处理触摸:
View.dispatchTouchEvent () 如果存在,首先向监听器发送事件 View.OnTouchListener.onTouch () 如果未被消费,则处理触摸本身 View.onTouchEvent ()
ViewGroup如何处理触摸:
ViewGroup.dispatchTouchEvent() onInterceptTouchEvent() Check if it should supersede children Passes ACTION_CANCEL to active child If it returns true once, the ViewGroup consumes all subsequent events For each child view (in reverse order they were added) If touch is relevant (inside view), child.dispatchTouchEvent() If it is not handled by a previous, dispatch to next view If no children handles the event, the listener gets a chance OnTouchListener.onTouch() If there is no listener, or its not handled onTouchEvent() Intercepted events jump over the child step
他还在github.com/devunwired/上提供了定制触摸的示例代码。
Answer: Basically the dispatchTouchEvent() is called on every View layer to determine if a View is interested in an ongoing gesture. In a ViewGroup the ViewGroup has the ability to steal the touch events in his dispatchTouchEvent()-method, before it would call dispatchTouchEvent() on the children. The ViewGroup would only stop the dispatching if the ViewGroup onInterceptTouchEvent()-method returns true. The difference is that dispatchTouchEvent()is dispatching MotionEvents and onInterceptTouchEvent tells if it should intercept (not dispatching the MotionEvent to children) or not (dispatching to children).
你可以想象ViewGroup的代码或多或少是这样做的(非常简化):
public boolean dispatchTouchEvent(MotionEvent ev) {
if(!onInterceptTouchEvent()){
for(View child : children){
if(child.dispatchTouchEvent(ev))
return true;
}
}
return super.dispatchTouchEvent(ev);
}
其他回答
补充回答
以下是对其他答案的视觉补充。我的完整答案在这里。
ViewGroup的dispatchTouchEvent()方法使用onInterceptTouchEvent()来选择是否应该立即处理触摸事件(使用onTouchEvent())或继续通知其子方法的dispatchTouchEvent()。
你可以在这个视频https://www.youtube.com/watch?v=SYoN-OvdZ3M&list=PLonJJ3BVjZW6CtAMbJz1XD8ELUs1KXaTD&index=19和接下来的三个视频中找到答案。所有的触摸事件都解释得很好,它非常清楚,充满了例子。
主要区别:
•Activity. dispatchtouchevent (MotionEvent) -这允许您的Activity 来拦截所有的触摸事件,然后再将它们分派到 窗口。 •ViewGroup.onInterceptTouchEvent(MotionEvent) -这允许一个 ViewGroup来监视事件,因为它们被分派到子视图。
答:小
onInterceptTouchEvent出现在setOnTouchListener之前。
关于这些方法有很多困惑,但实际上并没有那么复杂。大部分的困惑是因为:
如果你的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;
}