Android touch事件傳遞

2021-06-26 13:53:59 字數 3503 閱讀 6736

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...