基礎(chǔ)知識點:
對于觸屏手機(jī)诲祸,我們在上面進(jìn)行的任何點擊、滑動掀序,也就是觸屏(Touch)活動帆焕,都會生成被封裝到一種叫MotionEvent的事件里,Android系統(tǒng)用一下六種類型來描述用戶的touch事件類型
ACTION_DOWN(按下)
ACTION_MOVE(屏幕滑動)
ACTION_UP(離開屏幕)
ACTION_POINTER_DOWN(多點觸屏?xí)r產(chǎn)生森枪,暫不講解)
ACTION_POINTER_UP(多點觸屏?xí)r產(chǎn)生视搏,暫不講解)
ACTION_CANCEL
MotionEvent里面包含豐富的數(shù)據(jù)信息,包括:Touch的位置(Touch location)审孽,Touch的觸點數(shù)(也即手指數(shù))县袱,Touch的時刻等等
一個完整的手勢(gesture)是以action_down開始,以action_up結(jié)束
事件流:action_down--->action_move--->action_move--->action_move.....--->action_up(中間的action_move事件是否發(fā)生取決于手勢是否發(fā)生移動)
想想你平常在桌面點擊打開app和頁面切換滑動時激發(fā)的事件流是否有所不同佑力?
事件的分發(fā)式散,攔截,響應(yīng)的機(jī)制(關(guān)鍵字:分發(fā)打颤,攔截暴拄,響應(yīng),消費)
想象:想象一下貪官貪污的一種情況:在某某貧困縣编饺,每年國家都會給予一定的資金補(bǔ)助(分發(fā)過程)乖篷,這筆錢(touch事件)經(jīng)過省政府(根布局),市政府(父布局)都沒人去貪污它(即沒人去攔截它)透且,那么這錢就繼續(xù)往下分發(fā)撕蔼,到了縣政府這里來,此時某某縣大領(lǐng)導(dǎo)(子view)想吃下這筆錢秽誊,那么他就不讓這錢逃過他的手了鲸沮,所以他進(jìn)行了攔截,攔截下來后锅论,就要對這錢進(jìn)行“處理”呀讼溺,這時就進(jìn)行了響應(yīng)和消費,以后只要這官不被抓最易,那么每年國家撥下來的資金都分發(fā)到他這里就被攔截及消費了怒坯。當(dāng)然還有另外一種情況(現(xiàn)實不大可能發(fā)生),就是整個過程沒有人貪污藻懒,那么錢就一步一步分發(fā)下去敬肚,發(fā)到縣以后,這些年貧困縣發(fā)展起來了束析,決定不要這筆錢了(響應(yīng)但不消費)艳馒,所以就把錢還給市政府,市政府也決定不要這錢(響應(yīng)但不消費),就又把錢交給省政府了
事件分發(fā)流程:從父布局到子布局:Activity--->RootView--->ViewGroup1--->ViewGroup1的子ViewGroup2 ---> Target View
事件的響應(yīng)流程:從子布局到父布局:Target View--->ViewGroup2--->ViewGroup1--->RootView--->activity
幾個規(guī)則:
所有的事件從activity的dispatchTouchevent()函數(shù)開始弄慰,從父布局到子布局往下分發(fā)第美,當(dāng)然每個布局在任何事件傳到它那里后都可進(jìn)行攔截
所有的事件順著界面布局層次往下分發(fā),分發(fā)完就回溯(上面的分發(fā)和響應(yīng)流程)陆爽,這一過程中一旦出現(xiàn)了消費什往,流程就停在消費的view那一層,view必須把a(bǔ)ction_down事件消費掉后慌闭,后續(xù)的這個手勢的其他的事件才會傳到這個view别威。
如果整個過程沒有view想消費這個事件,那么最終的回溯的結(jié)束點就是activity的onTouchEvent()驴剔。
幾個涉及的重要方法(view或viewgroup里的方法):
public boolean dispatchTouchEvent(Motion ev):事件分發(fā)方法省古,把當(dāng)前事件分發(fā)給下一子布局,是一個遞歸的調(diào)用函數(shù)丧失,返回true則表示事件被處理
public boolean onInterceptTouchEvent(MotionEvent event):事件攔截方法,根據(jù)事件類型進(jìn)行攔截豺妓,比如一個scrollview想攔截action_move這個事件,返回true則表示進(jìn)行了攔截
public boolean onTouchEvent(MotionEvent event):事件響應(yīng)處理方法布讹,可以在方法中把事件消費了琳拭,也可不消費,那么就回溯給上級去響應(yīng)和處理描验,返回true則表示事件被消費
整個分發(fā)和響應(yīng)過程的規(guī)則可以用以下的偽代碼(摘自《Android開發(fā)藝術(shù)探索》)表示:
public boolean dispatchTouchEvent(MotionEvent event){
? ? ?boolean consume=false;
? ? ?if(onInterceptTouchEvent(event)){
? ? ? ? ? ?consume=onTouchEvent(event);
? ? ?} else {?
? ? ? ? ? ?consume=ChildView.dispatchTouchEvent(event);
? ? ?}
? ? ?return consume;
}
以下根據(jù)實例講述過程:本截圖引用自全英文檔http://trinea.github.io/download/pdf/android/PRE_andevcon_mastering-the-android-touch-system.pdf
講解:此布局是在frameLayout里面嵌套一個普通的view白嘁,當(dāng)你按下的時候,會觸發(fā)down事件膘流,事件就從activity出發(fā)絮缅,由于此時沒有任何的布局對此感興趣(即沒攔截和消費),那么分發(fā)完后回溯會activity的onTouchEvent睡扬,后續(xù)發(fā)生的move和up事件盟蚣,這時Android系統(tǒng)會這么認(rèn)為:既然你整個布局所有組件連按下去的事件都不感興趣,后續(xù)發(fā)生的事件肯定也是不感興趣卖怜,所以事件move和up都不往下進(jìn)行分發(fā)和回溯了屎开,直接在activity自己調(diào)用onTouchEvent去處理
講解:此布局是在frameLayout里面嵌套一個button,當(dāng)你按下的時候马靠,會觸發(fā)down事件奄抽,事件就從activity出發(fā),由于此時button對此事件感興趣甩鳄,那么button的onTouchEvent就會對此進(jìn)行消費逞度,事件被消費后就不會再回溯了,后續(xù)發(fā)生的move和up事件妙啃,button也是感興趣档泽,也進(jìn)行了消費俊戳,所以整個流程就只走到了button的onTouchEvent方法
講解:此布局是在Scrollview里面嵌套一個button,當(dāng)你按下的時候馆匿,會觸發(fā)down事件抑胎,事件就從activity出發(fā),由于此時button對此事件感興趣渐北,而scrollView對此事件不感興趣阿逃,那么button的onTouchEvent就會對此進(jìn)行消費,事件被消費后就不會再回溯了赃蛛,后續(xù)發(fā)生的move和up事件恃锉,scrollview和button都感興趣,但是由于scrollview先拿到事件呕臂,進(jìn)行攔截和消費破托,所以事件流就沒走到button那里,那為什么還會走回activity的onTouchEvent呢诵闭,scrollview進(jìn)行攔截炼团,但不進(jìn)行消費澎嚣,也就是scrollview的onTouchEvent返回值是false疏尿,所以才會回溯給activity。