不詳細介紹事件分發的流程和邏輯。
這裏關注一下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之間進行事件的攔截等操作。