目錄
-
-
- 分發的事件
- View繼承關系
- 事件分發處理流程
- 事件分發
-
- 頂級View對點選事件的分發過程
- 事件處理
-
- 事件處理總結
-
分發的事件
首先事件分發主要分為
事件分發發生在ViewGroup中的dispatchTouchEvent中
action_move會觸發多次
View繼承關系
view中dispatchTouchEvent用來處理事件
viewgroup中dispatchTouchEvent用來分發事件,不處理事件,viewgroup直接交給view去處理事件
事件分發處理流程
viewgroup先走分發流程,再走處理流程
view隻走處理流程
點選事件的整個分發流程大概:
首先點選事件,壓到螢幕後,觸發觸屏,導緻驅動,再到核心這一塊,然後再慢慢的到安卓底層,安卓底層再到源碼的話,安卓是直接先到activity的dispatchTouchEvent
然後通過getWindow(window是一個抽象類,他隻有一個實作類就是PhoneWindow)調用PhoneWindow的superDispatchTouchEvent方法
然後會調用DecorView的superDispatchTouchEvent
然後調用父類的dispatchTouchEvent方法,這裡父類是FrameLayout,但其實是調用的viewgroup的dispatchTouchEvent方法
我們的activity,以及viewGroup容器,都是通過viewGroup的dispatchTouchEvent來進行分發的,然後再由view.dispatchTouchEvent進行處理
注意:
分發是從底層的view一層一層分發
處理是從頂層的view一層一層往上處理的
處理事件最先處理的是我們最先看到的容器,而分發流程正好相反
事件分發
現在來梳理一下事件分發
我們其實可以想象我們的螢幕是一個立體坐标系
首先點選事件産生時,先進入的是activity
activity的dispatchTouchEvent
然後交給PhoneWindow的superDispatchTouchEvent
然後再到DecorView的superDispatchTouchEvent
然後調用父類的dispatchTouchEvent
DecorView是繼承FrameLayout的,但是FrameLayout沒有重寫dispatchTouchEvent,
是以就到了我們的viewgroup的dispatchTouchEvent
而viewgroup是重寫了父類的dispatchTouchEvent,是以可以用來進行事件分發,而事件處理是交給了父類,也就是view
super.dispatchTouchEvent -->view.dispatchTouchEvent
繼續回到事件分發
頂級View對點選事件的分發過程
點選事件到達頂級View(一般是ViewGroup)以後,會調用ViewGroup的dispatchTouchEvent方法,主要邏輯是這樣的,
如果頂級ViewGroup攔截事件也就是onInterceptTouchEvent傳回ture,那麼事件就交給ViewGroup處理,
(處理:這時如果ViewGroup的setOnTouchListener被調用的話,則OnTouch會被調用,否則OntouchEvent會被調用,也就是說都調用的情況下,onTouch會屏蔽掉onTouchEvent。在onTouchEvent中,如果設定了setOnClickListener,那麼onClick會被調用,如果onTouch傳回ture,那麼不會調用onTouchEvent,也就不會調用onClick)
如果頂級ViewGroup不攔截事件,那麼事件會傳遞給它所在的點選事件鍊上的子View,這時子View的dispatchTouchEvent會被調用,到此為止,事件已經從頂級View傳遞給了下一層View,接下來的傳遞過程和頂級View是一緻的。如此循環就完成了整個事件的分發。
事件處理
我們先建立一個Button,然後通過點選事件調用button的onClick和onTouch方法
如下:
在這裡提出三個問題:
1.onTouch的傳回值 有什麼用?
2.onClick和onTouch哪個會先調用?
3.在哪裡調用?
event對應事件
ACTION_DOWN = 0;//按下
ACTION_UP = 1;//離開
ACTION_MOVE = 2;//滑動
ACTION_CANCEL = 3;//事件被上層攔截
如果onTouch傳回ture,會出現什麼情況?onClick和onTouch方法中的日志都會列印嗎?
答案如下:隻有onTouch方法中log會列印,
如果onTouch傳回false呢?
這裡是onTouch和onClick都會執行,而且 注意是onTouch先執行,
—>可見onTouch的傳回值決定oclick是否執行
我們的事件處理在view.dispatchTouchEvent裡面,主要是在這段代碼裡執行
最外層的if判斷點選事件是否安全,一般來說我們的點選事件都是安全的。
然後判斷mListenerInfo是否為空。這裡我們需要看到前面的
setOnClickListener或者setOnTouchListener方法裡面,
再看到getListenerInfo裡面
這裡有一個單例模式,如果mListenerInfo不為空那麼直接傳回,否則建立一個mListenerInfo。
是以mListenerInfo肯定不為空。
再看到li.mOnTouchListener != null這個判斷。
這個地方其實在
調用方法的時候就已經new好了。是以這裡也是不為空的。
(mViewFlags & ENABLED_MASK) == ENABLED表示是否控件是可以點選的
然後就到了li.mOnTouchListener.onTouch(this, event),在這裡執行了onTouch。
如果onTouch傳回了false,result就會傳回false。如果onTouch傳回了true,result就會傳回true。
然後在下面接着又有一個判斷,這裡的意思是result為false的話onTouchEvent就會執行,為true就不會執行
是以我們可以推測onclick方法在onTouchEvent方法裡面執行
進一步推測onTouchEvent方法不一定是執行的。當onTouch傳回ture,result傳回ture的時候就不會。、
再回到onclick的執行,我們可以發現log日志列印,onclick是在ACTION_UP 之後執行的,是以我們可以看到switch判斷下
case MotionEvent.ACTION_UP:中的
看到這個PerformClick方法
然後進入performClickInternal方法
繼續performClick方法
诶,有沒有一種撥開雲霧見光明的感覺
playSoundEffect(SoundEffectConstants.CLICK);//對點選聲音的處理
事件處理總結
總結順序就是
dispatchTouchEvent —>onTouch —> onTouchEvent —> onClick
如果onTouch傳回true,就不會繼續了