前言ide
Android中關於觸摸事件的分發傳遞是一個很值得研究的東西。曾不見你引入了一個ListView的滑動功能,ListView就不聽你手指的指喚來滾動了;也不知道爲啥Button設置了onClick和onTouch,其中誰會先響應;或許你會問onTouch和onTouchEvent有什麼區別,又該如何使用?這裏一切的一切,只要你瞭解了事件分發機制,你會發現,解釋這都不是事兒!工具
相關Touch事件的方法spa
一、public boolean dispatchTouchEvent(MotionEvent ev) ————事件分發方法,分發Event所調用3d
二、public boolean onInterceptTouchEvent(MotionEvent ev) ————事件攔截方法,攔截Event所調用code
三、public boolean onTouchEvent(MotionEvent event) ————事件響應方法,處理Event所調用blog
擁有上述事件的類繼承
一、Activity類(Activity及其各類繼承子類)事件
dispatchTouchEvent()、onTouchEvent()get
二、ViewGroup類(LinearLayout、FrameLayout、ListView等.....)博客
dispatchTouchEvent()、onInterceptTouchEvent()、onTouchEvent()
三、View類(Button、TextView等.....)
dispatchTouchEvent()、onTouchEvent()
PS:須要特別注意一點就是ViewGroup中額外擁有onInterceptTouchEvent()方法,其餘兩個方法爲這三種類所共同擁有。
方法的簡單用途解析
咱們能夠發現這三個方法的返回值都爲boolean類型,其實它們就是經過返回值來決定下一步的傳遞處理方向。
一、dispatchTouchEvent() ——用來分發事件所用
該方法會將根元素的事件自上而下依次分發到內層子元素中,直到被終止或者到達最裏層元素,該方法也是採用一種隧道方式來分發。在其中會調用onInterceptTouchEvent()和onTouchEvent(),通常不會去重寫。
返回false則不攔截繼續往下分發,若是返回true則攔截住該事件不在向下層元素分發,在dispatchTouchEvent()方法中默認返回false。
二、onInterceptTouchEvent() ——用來攔截事件所用
該方法在ViewGroup源代碼中實現就是返回false不攔截事件,Touch事件就會往下傳遞給其子View。
若是咱們重寫該方法而且將其返回true,該事件將會被攔截,而且被當前ViewGroup處理,調用該類的onTouchEvent()方法。
三、onTouchEvent() ——用來處理事件
返回true則表示該View能處理該事件,事件將終止向上傳遞(傳遞給其父View)
返回false表示不能處理,則把事件傳遞給其父View的onTouchEvent()方法來處理
實戰演練
好了,基礎知識講完了,上面的東西看不懂沒關係,如今要睜大眼睛好好看了,由於下面開始用例子講解Touch的事件分發機制,相信能讓你們更好的理解這個分發機制。
在這個例子中,咱們須要重寫四個類:
一、老闆 ——> MyActivity
二、經理 ——> FrameLayout
三、組長 ——> LineaLayout
四、員工 ——> TextView
軟件界面圖以下:
【搞個通俗易懂的例子開開頭】
一、按常理,領導都會把任務向下分派,一旦下面的人把事情作很差,就不會再把後續的任務交給下面的人來作了,只能本身親自作,若是本身也作不了,就只能告訴上級不能完成任務,上級又會重複他的過程。
二、另外,領導都有權利攔截任務,對下級隱瞞該任務,而直接本身去作,若是作不成,也只能向上級報告不能完成任務。
流程演示
【1】、咱們假設員工能力不足,也就是將TextView的onTouchEvent()方法設置返回false,表示其不能消費該事件。
事件傳遞的流程:
【2】、咱們假設員工能處理該事件,也就是將TextView的onTouchEvent()方法設置返回true,表示其能處理該事件。
事件傳遞的流程:
【3】、咱們假設員工和組長能力不足,即TextView和LinearLayout的onTouch()返回false,可是經理解決了該問題,即FrameLayout的onTouch()返回true
事件傳遞的流程:
【4】假設咱們的組長在事件分發到他那裏的時候,決定攔截下來不交給下面的員工,也就是onInterceptTouchEvent()返回爲true,而且他也成功完成了任務,即onTouchEvent()返回值爲true。
事件傳遞的流程:
作個小結
一、很明顯,這些流程就是dispatchTouchEvent()的處理結果,可是前提是咱們不去徹底的從新實現這個方法,也就是保證須要return super.dispatchTouchEvent(ev);來肯定父類的方法有被調用。而這些事件將會由上而下的逐層傳遞,直到傳遞到最底層的View元素,此時將會調用該View的onTouchEvent()方法來處理該事件;返回true來表示對該事件已經成功處理,若是返回false則並無成功處理事件,將會把事件逐層向上傳遞,交給上層View的onTouchEvent()方法處理,以此類推,直至某一View成功處理該事件,或者到頂層View處理仍然返回false則放棄對該事件處理,事件消失。
二、若是在事件向下傳遞的過程當中,被中途攔截,也就是View的onInterceptTouchEvent()方法返回true,那麼該事件將中止向下傳遞,並交給該層的onTouchEvent()方法處理,不管處理成功與否,底層View將不再會接收到該事件。PS:若處理失敗,則會交由上層View的onTouchEvent()方法處理。
三、dispatchTouchEvent()具備記憶的功能,若是第一次事件向下傳遞到某View,它把事件繼續傳遞交給它的子View,它會記錄該事件是否被它下面的View給處理成功了,(怎麼能知道呢?若是該事件會再次被向上傳遞到我這裏來由個人onTouchEvent()來處理,那就說明下面的View都沒能成功處理該事件);當第二次事件向下傳遞到該View,該View的dispatchTouchEvent()方法機會判斷,若上次的事件由下面的view成功處理了,那麼此次的事件就繼續交給下面的來處理,若上次的事件沒有被下面的處理成功,那麼此次的事件就不會向下傳遞了,該View直接調用本身的onTouchEvent()方法來處理該事件。
四、記憶功能的信息只在一系列事件完成以前有效,如從ACTION_DOWN事件開始,直到後續事件ACTION_MOVE,ACTION_UP結束後,「記憶」的信息就會清除。也就是說若是某View處理ACTION_DOWN事件失敗了(onTouchEvent()返回false),那麼後續的ACTION_MOVE,ACTION_UP等事件就不會再傳遞到該View了,由其父View本身來處理。在下一次發生ACTION_DOWN事件的時候,仍是會傳遞到該View的。
附帶代碼
一、MyActivity
public class MyActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i("test", "【老闆】下達任務:" + Util.actionToString(ev.getAction()) + ",找我的幫我完成,任務往下分發。"); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { boolean relust = false; Log.i("test", "【老闆】完成任務:" + Util.actionToString(event.getAction()) + ",【經理】太差勁了,之後再也不找你幹活了,我自來搞定!是否解決:" + Util.canDoTaskTop(relust)); return relust; } }
二、MyFrameLayout:
public class MyFrameLayout extends FrameLayout { public MyFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i("test", "【經理】下達任務:" + Util.actionToString(ev.getAction()) + ",找我的幫我完成,任務往下分發。"); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean relust = false; Log.i("test", "【經理】是否攔截任務:" + Util.actionToString(ev.getAction()) + ",攔下來?" + relust); return relust; } @Override public boolean onTouchEvent(MotionEvent event) { boolean relust = true; Log.i("test", "【經理】完成任務:" + Util.actionToString(event.getAction()) + ",【組長】太差勁了,之後再也不找你幹活了,我自來搞定!是否解決:" + Util.canDoTask(relust)); return relust; } }
三、MyLinearLayout
public class MyLinearLayout extends LinearLayout { public MyLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i("test", "【組長】下達任務:" + Util.actionToString(ev.getAction()) + ",找我的幫我完成,任務往下分發。"); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean relust = true; Log.i("test", "【組長】是否攔截任務:" + Util.actionToString(ev.getAction()) + ",攔下來?" + relust); return relust; } @Override public boolean onTouchEvent(MotionEvent event) { boolean relust = true; Log.i("test", "【組長】完成任務:" + Util.actionToString(event.getAction()) + ",【員工】太差勁了,之後再也不找你幹活了,我自來搞定!是否解決:" + Util.canDoTask(relust)); return relust; } }
四、MyTextView
public class MyTextView extends TextView { public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.i("test", "【員工】下達任務:" + Util.actionToString(event.getAction()) + ",我沒手下了,唉~本身幹吧"); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { boolean relust = false; Log.i("test", "【員工】完成任務:" + Util.actionToString(event.getAction()) + ",【員工】如今只能靠本身了!是否解決:" + Util.canDoTask(relust)); return relust; } }
五、Util(工具類)
public class Util { public static String actionToString(int action){ String result = null; switch(action){ case MotionEvent.ACTION_DOWN: result = "ACTION_DOWN"; break; case MotionEvent.ACTION_MOVE: result = "ACTION_MOVE"; break; case MotionEvent.ACTION_UP: result = "ACTION_UP"; break; } return result; } public static String canDoTask(boolean can){ String result = null; if(can){ result = "完美解決該任務!"; } else{ result = "這活搞不定,交給老大完成吧。"; } return result; } public static String canDoTaskTop(boolean can){ String result = null; if(can){ result = "完美解決該任務!"; } else{ result = "這活搞不定,放棄該任務。"; } return result; } }
做者:enjoy風鈴
出處:http://www.cnblogs.com/net168/
本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然下次不給你轉載了