android的touch事件分發機制,涉及到每一層級的處理和傳遞,比較複雜,本文是在參考以下日誌和android原始碼的基礎上總結的,在此表示感謝:
1.touch事件傳遞過程
touch事件經過android核心層的處理,最終會傳遞到activity的dispatchtouchevent方法,由此開始一層層往下傳遞。即touch事件是從頂層開始一級級往下傳的,從activity傳到觸控到的viewgroup,再從viewgroup一層層往下傳,直到最底層的view,傳遞到每一層的都是dispatchtouchevent方法。
更為關鍵的是,touch操作分為action_down以及後續的action_move、action_cancel或action_up。這一系列事件被作為乙個整體,如果某一層的dispatchtouchevent返回了false,則後續的move等事件則不會再傳遞到該層(具體見下文的原始碼分析)。
2.view預設dispatchtouchevent方法
從1的分析可知,如果上層viewgroup均不消費touch事件,最終會呼叫子view的dispatchtouchevent方法,view類中該方法原始碼如下:
public boolean dispatchtouchevent(motionevent event)
if (onfiltertoucheventforsecurity(event))
if (ontouchevent(event))
}if (minputeventconsistencyverifier != null)
return false;
}
從第九行**可以看出,當該view存在ontouchlistener時,dispatchtouchevent會先觸發該listener,並且當ontouchlistener中的ontouch方法返回true時,dispatchtouchevent直接返回true,表示該view消費了該事件。如果不存在ontouchlistener或者ontouch方法返回false,會繼續呼叫view中的ontouchevent方法,如果該方法返回true,dispatchtouchevent返回true,否則返回false。
由此可以看出,在view中,ontouchlistener的優先順序高於ontouchevent,如果ontouchlistener消費了該事件,則不會去呼叫ontouchevent。
接下來我們看一下view預設的ontouchevent實現:
public boolean ontouchevent(motionevent event)
// a disabled view that is clickable still consumes the touch
// events, it just doesn't respond to them.
return (((viewflags & clickable) == clickable ||
(viewflags & long_clickable) == long_clickable));//view為disabled,但clickable時,仍返回true
}if (mtouchdelegate != null)
}if (((viewflags & clickable) == clickable ||
(viewflags & long_clickable) == long_clickable))
if (!post(mperformclick)) }}
。。。}
break;
case motionevent.action_down:
。。。break;
case motionevent.action_cancel:
setpressed(false);
removetapcallback();
removelongpresscallback();
break;
case motionevent.action_move:
。。。break;
}return true; //如果該view是clickable,必然會返回true
}return false;
}
**比較長,為了便於理解,我已經略去了一些。重點是該方法的返回值,從**可以看出,只要該view是clickable,則該方法必然返回true,從而使dispatchtouchevent方法返回true(前提是能走到該方法)。因此,如果是乙個button控制項,由於其預設是clickable的,所以即使未新增onclick事件,仍然會消費touch事件,而imageview由於預設非clickable,所以如果不做處理,touch事件在ontouch_down之後,由於
dispatchtouchevent返回false,後續的move、up事件則不會傳到該view。
3.viewgroup的dispatchtouchevent方法
viewgroup中dispatchtouchevent要相對複雜一些,其主要流程如下:
判斷是否允許攔截touch事件,如果允許,則呼叫onintercepttouchevent方法,如果onintercepttouchevent返回true,代表攔截該事件,dispatchtouchevent直接返回,否則繼續往下走;
尋找包含touch的座標點的子view(可能為view也可能為viewgroup),然後將touch事件傳到該view的dispatchtouchevent方法。如果某乙個子view的dispatchtouchevent返回true,則將該view標記為targetview,後續的move、up等事件會直接傳到該view,如果未找到這樣的子view,則呼叫該viewgroup的super.dispatchtouchevent方法,viewgroup的父類即view,view的dispatchtouchevent方法我們已經在上面分析過了,由此可見,如果子view未能消費該事件,則會去呼叫viewgroup的ontouch或ontouchevent方法。
這裡有乙個需要注意的地方:onintercepttouchevent的呼叫時機。原始碼如下:
if (actionmasked == motionevent.action_down
|| mfirsttouchtarget != null) else
} else
前兩行是說,如果該事件是
action_down
事件,或者已經找到了上面說的targetview。第三行是在判斷是否允許攔截,該flag通過requestdisallowintercepttouchevent設定。通過前兩行我們可以看出,在預設允許攔截的情況下,action_down事件是一定會走onintercepttouchevent的,並且如果未能找到targetview,在後續的move、up中,是不會走onintercepttouchevent。通過實驗,我發現當action_down找到targetview後,如果在action_move中將該事件攔截,則後續的up事件不會去調onintercepttouchevent,猜測可能在viewgroup攔截事件後將targetview置空。
android touch事件解析
android touch事件 乙個簡單的觸控螢幕所經歷的事件 action down action move action move action move.action move action up,即乙個acitondown,多個actionmove,乙個actionup android每個g...
android Touch事件流程
當乙個事件來臨的時候,會先傳遞給最外層的viewgroup 父view,比如linearlayout,framelayout 如果這個viewgroup沒有去攔截這個事件的話,才會給傳遞給下層的viewgroup或者view。如果被攔截掉的話,它會自己去處理這個事件,這個viewgroup內的子vi...
Android Touch事件分發
事件 viewgroup view有子元素 view無子元素 activity 方法功能 public boolean dispatchtouchevent motionevent ev yy ny分發 public boolean onintercepttouchevent motionevent...