安卓事件分發?超簡單~
平時寫程式碼,以業務為主,作為一個菜逼,總是覺得把工作做完就行,也就沒那麼關注原理。隨著工作年齡的增加,對各個控制元件的原理也就是模模糊糊的,講不清,道不明。某天突然腦抽,想寫一系列進階的文章,鞏固下基礎,補全那亂七八糟的理解。
今天來探討一下view的分發機制。
平時寫xml,對控制元件的使用就是一個layout包個layout,一個節點一個節點的下來。可系統怎麼知道我點的是這個控制元件,而不是包著他的那個父控制元件呢?
咱們先來個生動形象的爺爺爸爸兒子控制元件。

全家福.png
這其中代表著最普遍的巢狀關係
爺爺:rootlayout(根佈局)
爸爸:viewgroup(內部的layout等)
兒子:view(如button,textview等)
咱們非常清楚,這裡爺爺最年長,所以爸爸要聽爺爺的話。
那麼兒子就要聽爸爸的話。
所以我們的事件分發順序就是:
rootlayout(“爺爺”) -> viewgroup(“爸爸”) -> view(“兒子”)
每個成員都有dispatchTouchEvent(MotionEvent ev)方法,用來分發事件。
“兒子”最小,事件到了他這裡,他不能攔截,要麼消費掉,要麼再回傳,因為“兒子”沒地方分發事件,也就沒有可攔截的地方。
方法 | rootLayout | viewGroup | view |
---|---|---|---|
dispatchTouchEvent(分發) | 有 | 有 | 有 |
onInterceptTouchEvent(攔截) | 有 | 有 | 沒有 |
onTouchEvent(消費) | 有 | 有 | 有 |

消費路徑.png
- 我們把event看做是“糖果”
爺爺得到了一個糖果,進入dispatchTouchEvent(),呼叫了onInterceptTouchEvent(),如果合口味,那就返回true,攔截了該事件,交給onTouchEvent()處理;不攔截,就傳遞給下一個viewgroup
//rootlayout @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { Log.d(TAG, "rootview dispatchTouchEvent: 我得到了一個糖果"); } return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { Log.d(TAG, "rootview onInterceptTouchEvent:true 我要自己吃這個糖果"); return true; } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { Log.d(TAG, "rootview onTouchEvent: 爺爺自己吃了糖果"); } return super.onTouchEvent(event); }
D////爺爺///: rootview dispatchTouchEvent: 我得到了一個糖果 D////爺爺///: rootview onInterceptTouchEvent:true 我要自己吃這個糖果 D////爺爺///: rootview onTouchEvent: 爺爺自己吃了糖果
現在糖果不合“爺爺”口味,太硬了,磕牙~
事件傳遞給“爸爸”。
// viewgroup @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { Log.d(TAG, "viewGroup dispatchTouchEvent: 爸爸從爺爺那得到一顆糖~"); } return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (ev.getAction()==MotionEvent.ACTION_DOWN){ Log.d(TAG, "viewGroup onInterceptTouchEvent:我也不要吃 "); } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction()==MotionEvent.ACTION_DOWN){ Log.d(TAG, "viewGroup onTouchEvent: 我消費~"); } return super.onTouchEvent(event); } // view @Override public boolean dispatchTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { Log.d(TAG, "View1 dispatchTouchEvent: 兒子從爸爸那得到一顆糖 "); } return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { Log.d(TAG, "View1 onTouchEvent: true 兒子吃了糖果"); return true; } return super.onTouchEvent(event); }
D////爺爺///: rootview dispatchTouchEvent: 我得到了一個糖果 D////爺爺///: rootview onInterceptTouchEvent:false 我不要吃這個糖果 D////爸爸///: viewGroup dispatchTouchEvent: 爸爸從爺爺那得到一顆糖~ D////爸爸///: viewGroup onInterceptTouchEvent:我也不要吃 D////兒子///: View1 dispatchTouchEvent: 兒子從爸爸那得到一顆糖 D////兒子///: View1 onTouchEvent: true 兒子吃了糖果
如果“兒子”也不要吃糖果,onTouchEvent返回false,回傳給上一層的onTouchEvent,根據返回的true或者false來決定是否要消費。
//view @Override public boolean dispatchTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { Log.d(TAG, "View1 dispatchTouchEvent: 兒子從爸爸那得到一顆糖 "); } return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { Log.d(TAG, "View1 onTouchEvent: false 我不要吃"); return false; } return super.onTouchEvent(event); }
D////爺爺///: rootview dispatchTouchEvent: 我得到了一個糖果 D////爺爺///: rootview onInterceptTouchEvent:false 我不要吃這個糖果 D////爸爸///: viewGroup dispatchTouchEvent: 爸爸從爺爺那得到一顆糖~ D////爸爸///: viewGroup onInterceptTouchEvent:我也不要吃 D////兒子///: View1 dispatchTouchEvent: 兒子從爸爸那得到一顆糖 D////兒子///: View1 onTouchEvent: false 我不要吃 D////爸爸///: viewGroup onTouchEvent: true 兒子不吃,那我吃
至此,事件分發的大致流程在爺孫三謙讓的分糖果過程中完全體現。如有錯誤處與改進處,請給我留言,謝謝~