Android中onInterceptTouchEvent和dispatchTouchEvent的区别是什么?
根据android开发者指南,这两种方法都可以用来拦截触摸事件(MotionEvent),但有什么区别呢?
onInterceptTouchEvent, dispatchTouchEvent和onTouchEvent如何在视图(ViewGroup)的层次结构中一起交互?
Android中onInterceptTouchEvent和dispatchTouchEvent的区别是什么?
根据android开发者指南,这两种方法都可以用来拦截触摸事件(MotionEvent),但有什么区别呢?
onInterceptTouchEvent, dispatchTouchEvent和onTouchEvent如何在视图(ViewGroup)的层次结构中一起交互?
当前回答
揭开这一神秘面纱的最佳地点是源代码。医生们对这一点解释得很不充分。
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更倾向于灵活性而不是简单性。
其他回答
在拦截事件之前发出指示。
用这个简单的例子:
main = new LinearLayout(this){
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
System.out.println("Event - onInterceptTouchEvent");
return super.onInterceptTouchEvent(ev);
//return false; //event get propagated
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
System.out.println("Event - dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
//return false; //event DONT get propagated
}
};
main.setBackgroundColor(Color.GRAY);
main.setLayoutParams(new LinearLayout.LayoutParams(320,480));
viewA = new EditText(this);
viewA.setBackgroundColor(Color.YELLOW);
viewA.setTextColor(Color.BLACK);
viewA.setTextSize(16);
viewA.setLayoutParams(new LinearLayout.LayoutParams(320,80));
main.addView(viewA);
setContentView(main);
你可以看到日志是这样的:
I/System.out(25900): Event - dispatchTouchEvent
I/System.out(25900): Event - onInterceptTouchEvent
因此,如果你正在使用这两个处理程序,使用dispatchTouchEvent来处理第一个实例的事件,这将去onInterceptTouchEvent。
另一个区别是,如果dispatchTouchEvent返回'false',事件不会被传播到子,在这种情况下的EditText,而如果你在onInterceptTouchEvent返回false,事件仍然得到调度到EditText
因为这是谷歌的第一个结果。我想在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);
}
你可以在这个视频https://www.youtube.com/watch?v=SYoN-OvdZ3M&list=PLonJJ3BVjZW6CtAMbJz1XD8ELUs1KXaTD&index=19和接下来的三个视频中找到答案。所有的触摸事件都解释得很好,它非常清楚,充满了例子。
补充回答
以下是对其他答案的视觉补充。我的完整答案在这里。
ViewGroup的dispatchTouchEvent()方法使用onInterceptTouchEvent()来选择是否应该立即处理触摸事件(使用onTouchEvent())或继续通知其子方法的dispatchTouchEvent()。
主要区别:
•Activity. dispatchtouchevent (MotionEvent) -这允许您的Activity 来拦截所有的触摸事件,然后再将它们分派到 窗口。 •ViewGroup.onInterceptTouchEvent(MotionEvent) -这允许一个 ViewGroup来监视事件,因为它们被分派到子视图。