Android觸控式螢幕事件派發機制詳解與原始碼分析一(View篇)
【工匠若水 http://blog.csdn.net/yanbober】
Notice:閱讀完該篇之後如果想繼續深入閱讀Android觸控式螢幕事件派發機制詳解與原始碼分析下一篇請點選《Android觸控式螢幕事件派發機制詳解與原始碼分析二(ViewGroup篇)》檢視。
1 背景
最近在簡書和微博還有Q群看見很多人說Android自定義控制元件(View/ViewGroup)如何學習?為啥那麼難?其實答案很簡單:“基礎不牢,地動山搖。”
不扯蛋了,進入正題。就算你不自定義控制元件,你也必須要了解Android控制元件的觸控式螢幕事件傳遞機制(之所以說觸控式螢幕是因為該系列以觸控式螢幕的事件機制分析為主,對於類似TV裝置等的物理事件機制的分析雷同但有區別。哈哈,誰讓我之前是做Android TV BOX的,悲催!),只有這樣才能將你的控制元件事件運用的如魚得水。接下來的控制元件觸控式螢幕事件傳遞機制分析依據Android 5.1.1原始碼(API 22)。
2 基礎例項現象
2-1 例子
從一個例子分析說起吧。如下是一個很簡單不過的Android例項:
<code class="language-xml hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-pi" style="color: rgb(0, 102, 102); box-sizing: border-box;"><?xml version="1.0" encoding="utf-8"?></span> <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">LinearLayout</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">xmlns:android</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"http://schemas.android.com/apk/res/android"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:orientation</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"vertical"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:gravity</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"center"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_width</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"fill_parent"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_height</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"fill_parent"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:id</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"@+id/mylayout"</span>></span> <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">Button </span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:id</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"@+id/my_btn"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_width</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"match_parent"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_height</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"wrap_content"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:text</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"click test"</span>/></span> <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">LinearLayout</span>></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>
<code class="language-android hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ListenerActivity</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Activity</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">View</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">OnTouchListener</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">View</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">OnClickListener</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> LinearLayout mLayout; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> Button mButton; <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onCreate</span>(Bundle savedInstanceState) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onCreate(savedInstanceState); setContentView(R.layout.main); mLayout = (LinearLayout) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.findViewById(R.id.mylayout); mButton = (Button) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.findViewById(R.id.my_btn); mLayout.setOnTouchListener(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>); mButton.setOnTouchListener(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>); mLayout.setOnClickListener(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>); mButton.setOnClickListener(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>); } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">onTouch</span>(View v, MotionEvent event) { Log.i(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"OnTouchListener--onTouch-- action="</span>+event.getAction()+<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" --"</span>+v); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>; } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onClick</span>(View v) { Log.i(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"OnClickListener--onClick--"</span>+v); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li></ul>
2-2 現象
如上程式碼很簡單,但凡學過幾天Android的人都能看懂吧。Activity中有一個LinearLayout(ViewGroup的子類,ViewGroup是View的子類)佈局,佈局中包含一個按鈕(View的子類);然後分別對這兩個控制元件設定了Touch與Click的監聽事件,具體執行結果如下:
- 當穩穩的點選Button時列印如下:
- 當穩穩的點選除過Button以外的其他地方時列印如下:
- 當收指點選Button時按在Button上晃動了一下鬆開後的列印如下:
機智的你看完這個結果指定知道為啥吧?
我們看下onTouch和onClick,從引數都能看出來onTouch比onClick強大靈活,畢竟多了一個event引數。這樣onTouch裡就可以處理ACTION_DOWN、ACTION_UP、ACTION_MOVE等等的各種觸控。現在來分析下上面的列印結果;在1中,當我們點選Button時會先觸發onTouch事件(之所以列印action為0,1各一次是因為按下擡起兩個觸控動作被觸發)然後才觸發onClick事件;在2中也同理類似1;在3中會發現onTouch被多次調運後才調運onClick,是因為手指晃動了,所以觸發了ACTION_DOWN->ACTION_MOVE…->ACTION_UP。
如果你眼睛比較尖你會看見onTouch會有一個返回值,而且在上面返回了false。你可能會疑惑這個返回值有啥效果?那就驗證一下吧,我們將上面的onTouch返回值改為ture。如下:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">onTouch</span>(View v, MotionEvent event) { Log.i(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"OnTouchListener--onTouch-- action="</span>+event.getAction()+<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" --"</span>+v); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>
再次點選Button結果如下:
看見了吧,如果onTouch返回true則onClick不會被調運了。
2-3 總結結論
好了,經過這個簡單的例項驗證你可以總結髮現:
- Android控制元件的Listener事件觸發順序是先觸發onTouch,其次onClick。
- 如果控制元件的onTouch返回true將會阻止事件繼續傳遞,返回false事件會繼續傳遞。
對於伸手黨碼農來說其實到這足矣應付常規的App事件監聽處理使用開發了,但是對於複雜的事件監聽處理或者想自定義控制元件的碼農來說這才是剛剛開始,只是個熱身。既然這樣那就繼續嘍。。。
3 Android 5.1.1(API 22) View觸控式螢幕事件傳遞原始碼分析
3-1 寫在前面的話
其實Android原始碼無論哪個版本對於觸控式螢幕事件的傳遞機制都類似,這裡只是選用了目前最新版本的原始碼來分析而已。分析Android View事件傳遞機制之前有必要先看下原始碼的一些關係,如下是幾個繼承關係圖:
怎麼樣?看了官方這個繼承圖是不是明白了上面例子中說的LinearLayout是ViewGroup的子類,ViewGroup是View的子類,Button是View的子類關係呢?其實,在Android中所有的控制元件無非都是ViewGroup或者View的子類,說高尚點就是所有控制元件都是View的子類。
這裡通過繼承關係是說明一切控制元件都是View,同時View與ViewGroup又存在一些區別,所以該模組才只單單先分析View觸控式螢幕事件傳遞機制。
3-2 從View的dispatchTouchEvent方法說起
在Android中你只要觸控控制元件首先都會觸發控制元件的dispatchTouchEvent方法(其實這個方法一般都沒在具體的控制元件類中,而在他的父類View中),所以我們先來看下View的dispatchTouchEvent方法,如下:
<code class="language-android hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> boolean <span class="hljs-title" style="box-sizing: border-box;">dispatchTouchEvent</span>(MotionEvent <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// If the event should be handled by accessibility focus first.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>.isTargetAccessibilityFocus()) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// We don't have focus or no virtual descendant has it, do not handle the event.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!isAccessibilityFocusedViewOrHost()) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// We have focus and got the event, then use normal event dispatch.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>.setTargetAccessibilityFocus(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>); } boolean result = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mInputEventConsistencyVerifier != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { mInputEventConsistencyVerifier.onTouchEvent(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); } final <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> actionMasked = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>.getActionMasked(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (actionMasked == MotionEvent.ACTION_DOWN) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Defensive cleanup for new gesture</span> stopNestedScroll(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (onFilterTouchEventForSecurity(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>)) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//noinspection SimplifiableIfStatement</span> ListenerInfo li = mListenerInfo; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (li != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> && li.mOnTouchListener != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>)) { result = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!result && onTouchEvent(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>)) { result = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>; } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!result && mInputEventConsistencyVerifier != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { mInputEventConsistencyVerifier.onUnhandledEvent(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Clean up after nested scrolls if this is the end of a gesture;</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// also cancel it if we tried an ACTION_DOWN but we didn't want the rest</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// of the gesture.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (actionMasked == MotionEvent.ACTION_UP || actionMasked == MotionEvent.ACTION_CANCEL || (actionMasked == MotionEvent.ACTION_DOWN && !result)) { stopNestedScroll(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> result; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li></ul>
dispatchTouchEvent的程式碼有點長,咱們看重點就可以。前面都是設定一些標記和處理input與手勢等傳遞,到24行的if (onFilterTouchEventForSecurity(event))
語句判斷當前View是否沒被遮住等,接著26行定義ListenerInfo區域性變數,ListenerInfo是View的靜態內部類,用來定義一堆關於View的XXXListener等方法;接著if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event))
語句就是重點,首先li物件自然不會為null,li.mOnTouchListener呢?你會發現ListenerInfo的mOnTouchListener成員是在哪兒賦值的呢?怎麼確認他是不是null呢?通過在View類裡搜尋可以看到:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * Register a callback to be invoked when a touch event is sent to this view. *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> l the touch listener to attach to this view */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">setOnTouchListener</span>(OnTouchListener l) { getListenerInfo().mOnTouchListener = l; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
li.mOnTouchListener是不是null取決於控制元件(View)是否設定setOnTouchListener監聽,在上面的例項中我們是設定過Button的setOnTouchListener方法的,所以也不為null;接著通過位與運算確定控制元件(View)是不是ENABLED 的,預設控制元件都是ENABLED 的;接著判斷onTouch的返回值是不是true。通過如上判斷之後如果都為true則設定預設為false的result為true,那麼接下來的if (!result && onTouchEvent(event))
就不會執行,最終dispatchTouchEvent也會返回true。而如果if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event))
語句有一個為false則if (!result && onTouchEvent(event))
就會執行,如果onTouchEvent(event)返回false則dispatchTouchEvent返回false,否則返回true。
這下再看前面的例項部分明白了吧?控制元件觸控就會調運dispatchTouchEvent方法,而在dispatchTouchEvent中先執行的是onTouch方法,所以驗證了例項結論總結中的onTouch優先於onClick執行道理。如果控制元件是ENABLE且在onTouch方法裡返回了true則dispatchTouchEvent方法也返回true,不會再繼續往下執行;反之,onTouch返回false則會繼續向下執行onTouchEvent方法,且dispatchTouchEvent的返回值與onTouchEvent返回值相同。
所以依據這個結論和上面例項列印結果你指定已經大膽猜測認為onClick一定與onTouchEvent有關係?是不是呢?先告訴你,是的。下面我們會分析。
3-2-1 總結結論
在View的觸控式螢幕傳遞機制中通過分析dispatchTouchEvent方法原始碼我們會得出如下基本結論:
- 觸控控制元件(View)首先執行dispatchTouchEvent方法。
- 在dispatchTouchEvent方法中先執行onTouch方法,後執行onClick方法(onClick方法在onTouchEvent中執行,下面會分析)。
- 如果控制元件(View)的onTouch返回false或者mOnTouchListener為null(控制元件沒有設定setOnTouchListener方法)或者控制元件不是enable的情況下會調運onTouchEvent,dispatchTouchEvent返回值與onTouchEvent返回一樣。
- 如果控制元件不是enable的設定了onTouch方法也不會執行,只能通過重寫控制元件的onTouchEvent方法處理(上面已經處理分析了),dispatchTouchEvent返回值與onTouchEvent返回一樣。
- 如果控制元件(View)是enable且onTouch返回true情況下,dispatchTouchEvent直接返回true,不會呼叫onTouchEvent方法。
上面說了onClick一定與onTouchEvent有關係,那麼接下來就分析分析dispatchTouchEvent方法中的onTouchEvent方法。
3-3 繼續說說View的dispatchTouchEvent方法中調運的onTouchEvent方法
上面說了dispatchTouchEvent方法中如果onTouch返回false或者mOnTouchListener為null(控制元件沒有設定setOnTouchListener方法)或者控制元件不是enable的情況下會調運onTouchEvent,所以接著看就知道了,如下:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">onTouchEvent</span>(MotionEvent event) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> x = event.getX(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> y = event.getY(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> viewFlags = mViewFlags; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((viewFlags & ENABLED_MASK) == DISABLED) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) { setPressed(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// A disabled view that is clickable still consumes the touch</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// events, it just doesn't respond to them.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mTouchDelegate != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mTouchDelegate.onTouchEvent(event)) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>; } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">switch</span> (event.getAction()) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">case</span> MotionEvent.ACTION_UP: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((mPrivateFlags & PFLAG_PRESSED) != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> || prepressed) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// take focus if we don't have it already and we should in</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// touch mode.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> focusTaken = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (isFocusable() && isFocusableInTouchMode() && !isFocused()) { focusTaken = requestFocus(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (prepressed) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// The button is being released before we actually</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// showed it as pressed. Make it show the pressed</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// state now (before scheduling the click) to ensure</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// the user sees it.</span> setPressed(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>, x, y); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!mHasPerformedLongPress) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// This is a tap, so remove the longpress check</span> removeLongPressCallback(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Only perform take click actions if we were in the pressed state</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!focusTaken) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Use a Runnable and post this rather than calling</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// performClick directly. This lets other visual state</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// of the view update before click actions start.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mPerformClick == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { mPerformClick = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> PerformClick(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!post(mPerformClick)) { performClick(); } } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mUnsetPressedState == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { mUnsetPressedState = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> UnsetPressedState(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (prepressed) { postDelayed(mUnsetPressedState, ViewConfiguration.getPressedStateDuration()); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!post(mUnsetPressedState)) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// If the post failed, unpress right now</span> mUnsetPressedState.run(); } removeTapCallback(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">case</span> MotionEvent.ACTION_DOWN: mHasPerformedLongPress = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (performButtonActionOnTouchDown(event)) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Walk up the hierarchy to determine if we're inside a scrolling container.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> isInScrollingContainer = isInScrollingContainer(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// For views inside a scrolling container, delay the pressed feedback for</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// a short period in case this is a scroll.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (isInScrollingContainer) { mPrivateFlags |= PFLAG_PREPRESSED; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mPendingCheckForTap == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { mPendingCheckForTap = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> CheckForTap(); } mPendingCheckForTap.x = event.getX(); mPendingCheckForTap.y = event.getY(); postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Not inside a scrolling container, so show the feedback right away</span> setPressed(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>, x, y); checkForLongClick(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">case</span> MotionEvent.ACTION_CANCEL: setPressed(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>); removeTapCallback(); removeLongPressCallback(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">case</span> MotionEvent.ACTION_MOVE: drawableHotspotChanged(x, y); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Be lenient about moving outside of buttons</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!pointInView(x, y, mTouchSlop)) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Outside button</span> removeTapCallback(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((mPrivateFlags & PFLAG_PRESSED) != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Remove any future long press/tap checks</span> removeLongPressCallback(); setPressed(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>); } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding
相關推薦
Android觸控式螢幕事件派發機制詳解與原始碼分析一(View篇)
【工匠若水 http://blog.csdn.net/yanbober】 Notice:閱讀完該篇之後如果想繼續深入閱讀Android觸控式螢幕事件派發機制詳解與原始碼分析下一篇請點選《Android觸控式螢幕事件派發機制詳解與原始碼分析二(ViewGroup篇)》檢視。 1
Android觸控式螢幕事件派發機制詳解與原始碼分析三(Activity篇)
PS一句:最終還是選擇CSDN來整理髮表這幾年的知識點,該文章平行遷移到CSDN。因為CSDN也支援MarkDown語法了,牛逼啊! 【工匠若水 http://blog.csdn.net/yanbober】 該篇承接上一篇《Android觸控式螢幕事件派發機制詳解與原始碼分析
Android觸控式螢幕事件派發機制詳解與原始碼分析二(ViewGroup篇)
【工匠若水 http://blog.csdn.net/yanbober】 該篇承接上一篇《Android觸控式螢幕事件派發機制詳解與原始碼分析一(View篇)》,閱讀本篇之前建議先閱讀。當然,閱讀完這一篇之後可以閱讀繼續進階的下一篇《Android觸控式螢幕事件派發機制詳解與原始碼
Android非同步訊息處理機制詳解及原始碼分析
PS一句:最終還是選擇CSDN來整理髮表這幾年的知識點,該文章平行遷移到CSDN。因為CSDN也支援MarkDown語法了,牛逼啊! 【工匠若水 http://blog.csdn.net/yanbober 轉載煩請註明出處,尊重分享成果】 最近相對來說比較閒,加上養病,所
Android開發——事件分發機制詳解---微信魚蝦蟹源碼搭建
lai reset 微信 影響 ren 事件分發機制 lis forum hlist 轉載請註明出處:http://h5.hxforum.com深入學習事件分發機制,是為了解決在Android開發中遇到的滑動沖突問題做準備。事件分發機制描述了用戶的手勢一系列事件是如何被An
Android開發——事件分發機制詳解
0. 前言深入學習事件分發機制,是為了解決在Android開發中遇到的滑動衝突問題做準備。事件分發機制描述了使用者的手勢一系列事件是如何被Android系統傳遞並消費的。首先對事件分發機制進行概述:如果
springmvc處理請求詳解與原始碼分析
一、Dispatchservlet繼承體系 在我上一篇部落格中,我主要分析了springmvc體系的建立過程,主要是上圖中DispatcherServlet,它的父類FrameworkServlet,及HttpServletBean的建立過程,詳情可至 s
水平集詳解與程式碼分析一
前面我們從大體上描述了一下水平集方法的思想,實際上,各種水平集方法的區別只是在於如何構建能量函式E(C)。當構建好能量泛函E(C)之後,通過水平集的思想,將曲線C用水平集函式Φ代替,再通過求解能量泛函對應的Euler-Lagrange方程獲得水平集的演化方程。
Java 集合之 Set 詳解與原始碼分析
Set集合與List一樣,都是繼承自Collection介面,常用的實現類有HashSet和TreeSet。值得注意的是,HashSet是通過HashMap來實現的而TreeSet是通過TreeMap來實現的,所以HashSet和TreeSet都沒有自己的資料結構,具
Android事件分發機制詳解
概述 眾所周知,Android事件分發機制是Android知識體系中的重點也是難點。說白了,要學好Android,事件分發機制是無論如何也繞不過去的。 也許你會問,Android事件分發機制那麼重要,我怎麼沒用過呢? 當你被不同item的側滑刪除衝突
Android FrameWork——Touch事件派發過程詳解
對於android的視窗window管理,一直感覺很混亂,總想找個時間好好研究,卻不知如何入手,現在寫的Touch事件派發過程詳解,其實跟android的視窗window管理服務WindowManagerService存在緊密聯絡,所以從這裡入手切入到WindowManag
Android點選事件傳遞機制詳解
在講正題之前我們講一段有關任務傳遞的小故事,拋磚迎玉下: 話說一家軟體公司,來一個任務,分派給了開發經理去完成: 開發經理拿到,看了一下,感覺好簡單,於是 開發經理:分派給了開發組長 開發組長:分派給了自己組員(程式設計師) 程式設計師:分派給了自己帶的實習生。
View的事件體系之三 android事件分發機制詳解(下)
接著上一篇來分析事件分發機制,在看了各位大牛的關於事件分發機制的分析後茅塞頓開,之前看過好幾遍郭霖,弘揚以及玉剛大神關於事件體系的講解,一直看不懂,比較模糊,最近複習時,看到一篇博文,寫的相當精彩,看完後,再回看各位大神的博文,收穫頗豐,記錄一下自己的理解和
Android 事件分發機制詳解(1)
Android事件分發機制詳解(一) 所謂Android事件分發機制,其實也就是View的事件分發機制,在介紹事件的傳遞規則之前,首先我們要明白這裡需要分析的物件MotionEvent。 MotionEvent類 在手指接觸屏幕後所產生的事件封裝成了Mo
android 事件分發機制詳解
摘要: 整個事件分發就類似於分發任務是一樣的 老大分配任務給老二 、老二分配任務給老三 如果老三完成了,這個任務就結束了,如果老三沒有完成則會將任務
Android事件傳遞機制詳解(巢狀自定義View示例)
一、概述 自定義View如果嵌套了自定義View,可能簡單寫一個onTouchEvent處理事件已經不能解決你的需要。簡單舉個例子: 你自定義了一個容器View,簡稱為父View,在這裡監聽點選事件,做事情A,監聽滑動做事情B 然後你又自定了一個View,放入該容器
iOS事件傳遞機制詳解
概述 當用戶觸控實際螢幕時,會生成一個Touch Event,將此事件新增到UIApplication管理的事件佇列之中。 UIApplication從事件佇列之中按順序取出事件分發到檢視去處理。 當事件被髮出以後,會從keyWindow開始,依次向上傳遞,包括
安卓自定義View進階-事件分發機制詳解
Android 事件分發機制詳解,在上一篇文章 事件分發機制原理 中簡要分析了一下事件分發機制的原理,原理是十分簡單的,一句話就能總結:責任鏈模式,事件層層傳遞,直到被消費。 雖然原理簡單,但是隨著 Android 不斷的發展,實際運用場景也越來越複雜,所以想要徹底玩轉事件分發機制還
Zookeeper機制詳解與實現
為什麼要有Zookeeper? 電視裡經常會有一些狗血的設定,隊長和副隊長一起出去執行任務,執行完任務後副隊長回來報到了,但是隊長可能因為天氣原因導致航班延期了,暫時回不來,這個時候副隊長左等右等還等不到隊長回來,而且副隊長擔心隊長如
android matrix 最全方法詳解與進階
1 概述 這裡我們會詳細講解matrix的各個方法,以及它的用法。matrix叫做矩陣,在前面講解 ColorFilter 的文章中,我們講解了ColorMatrix,他是一個4*5的矩陣。而這裡,我們講解的Matrix不是用於處理顏色的,而是處理圖形的。他是一個3*3的