不详细介绍事件分发的流程和逻辑。
这里关注一下activity view对于touch/key事件接受处理的先后顺序。
既然是activity和view的事件接受顺序,那么只考虑dispatchTouchEvent和onTouchEvent;
直接看结果,然后再看why(你总的先看一眼妹子好不好看,然后在去提亲不是)
结果是:
1.dispatchTouchEvent:activity先响应,view后响应;
2.onTouchEvent:activity后响应,view先响应;
注意关键字‘先后’。
再看看why?
简单的,demo打堆栈,截取部分:
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:444)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1829)
at android.app.Activity.dispatchTouchEvent(Activity.java:3394)
at com.shixin398.myapplication.MainActivity.dispatchTouchEvent(MainActivity.java:31)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:68)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:402)
at android.view.View.dispatchPointerEvent(View.java:12567)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5031)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4834)
viewroot中processPointerEvent可能大部分人很陌生,没关系,不需要care;知道这个是进行touch事件派发的最早期入口就ok。
(搞事情,不要妄图一下啥都搞明白,慢慢来)
随后走到view中的dispatchPointerEvent,这个view实际是decorview,会走到decorview的dispatchTouchEvent。这个函数就比较熟悉了,经常需要复写的一个函数。
12062 public final boolean dispatchPointerEvent(MotionEvent event) {
12063 if (sDebugDispatchInput) {
12064 Log.d(VIEW_LOG_TAG, "dispatchPointerEvent event is TouchEvent ? "
12065 + event.isTouchEvent() + " ,event: " + event);
12066 }
12067 if (event.isTouchEvent()) {
12068 return dispatchTouchEvent(event);//当前view是decorview,多态么,就走decorview的方法
12069 } else {
12070 return dispatchGenericMotionEvent(event);
12071 }
12072 }
到decoreview就看下源码:
394 @Override
395 public boolean dispatchTouchEvent(MotionEvent ev) {
396 final Window.Callback cb = mWindow.getCallback();
397 return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
398 ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
399 }
一、dispatchTouchEvent:activity先响应,view后响应
window.callback,关于activity和窗口的关系,现在也不需要详细了解,知道这个callback对应当前的activity就ok。
那么就走到activity的dispatchTouchEvent了。
所以1点的逻辑就是刚才讲述的逻辑了:1.dispatchTouchEvent:activity先响应,view后响应;
如果activity拦截了事件,则decorview中的view不会收到touch事件。若不拦截,则会继续派发。
这个继续派发,也会看到2的逻辑分析,如下。
二、onTouchEvent:activity后响应,view先响应
如果activity没有拦截,那么会派发的viewgroup。看下acitivity code便知:
3396 public boolean dispatchTouchEvent(MotionEvent ev) {
3397 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
3398 onUserInteraction();
3399 }
3400 if (getWindow().superDispatchTouchEvent(ev)) {//通过getwindow来把事件给窗口,window在给decorview,decorview就给activity里的控件了(viewgroup/view)
3401 return true;
3402 }
3403 return onTouchEvent(ev);//最后是onTouchEvent,论证了2点
3404 }
代码中:
if (getWindow().superDispatchTouchEvent(ev))
getwindow拿到的是phonewidnow,代码如下:
1827 @Override
1828 public boolean superDispatchTouchEvent(MotionEvent event) {
1829 return mDecor.superDispatchTouchEvent(event);
1830 }
然后是decorview的,又看到熟悉的dispatchTouchEvent了:
474 public boolean superDispatchTouchEvent(MotionEvent event) {
475 return super.dispatchTouchEvent(event);
476 }
public class DecorView extends FrameLayout
public class FrameLayout extends ViewGroup
调用super的,而super是framelayout,里面没有复写dispatchTouchEvent,自然也就调用viewgroup中的dispatch了。
到viewgroup里就不在详细讲述了,这个事件链很麻烦,真心不想写。
知道viewgroup这里dispatchtouchevent 经过层层遍历递归,会最终调用到具体的view的OnTouchEvent就ok了。(可以看下任玉刚的书中写的这部分,或者csdn一下也ok)。
到此,知道通过activity的下面逻辑,走到viewgroup的dispatchTouchevent,随后递归派发touch事件。如果没有没有view响应,也就是return false了。
getWindow().superDispatchTouchEvent(ev)
才会执行activity的onTouchEvent。所以dispatchTouchEvent:activity先响应,view后响应;onTouchEvent:activity后响应,view先响应;
关键函数:activity的dispatchTouchEvent,先if最后return onTouchEvent。
3396 public boolean dispatchTouchEvent(MotionEvent ev) {
3397 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
3398 onUserInteraction();
3399 }
3400 if (getWindow().superDispatchTouchEvent(ev)) {//通过getwindow来把事件给窗口,window在给decorview,decorview就给activity里的控件了(viewgroup/view)
3401 return true;
3402 }
3403 return onTouchEvent(ev);//最后是onTouchEvent,论证了2点
3404 }
至此,结束。
只分析了dispatch 和onTouchEvent 在acitivity和view之间,调用的先后顺序,以便在进行事件处理时,可以合理的在自定义view和acitivity之间进行事件的拦截等操作。