Android Touch事件傳遞機制詳解 下

來源:互聯網
上載者:User

Android Touch事件傳遞機制詳解 下

 

 

在前一篇文章中,我主要講解了Android源碼中的Touch事件的傳遞過程,現在我想使用一個demo以及一個執行個體來學習一下Andorid中的Touch事件處理過程。

在Android系統中,和Touch事件分發和處理緊密相關的三個函數如下:
(1) public boolean dispatchTouchEvent(MotionEvent ev)
(2) public boolean onInterceptTouchEvent(MotionEvent ev)
(3) public boolean onTouchEvent(MotionEvent event)


這三個方法我在前一篇文章中都對他們的源碼進行了分析:方法1主要是對Touch事件進行分發,方法2主要是對Touch事件進行攔截,方法3是對Touch事件進行處理

這三個方法主要存在於ViewGroup,View,Activity中,具體情況如:

 

 

 

ViewGroup

View

Activity

dispatchTouchEvent

onInterceptTouchEvent

onTouchEvent


 

下面我們就使用一個demo來看看這些方法的執行流程:
自訂一個類:MyLayoutFirst.java

 

public class MyLayoutFirst extends LinearLayout{  private static final String TAG = MyLayoutFirst;  public MyLayoutFirst(Context context, AttributeSet attrs)  {    super(context, attrs);  }    @Override  public boolean onInterceptTouchEvent(MotionEvent ev)  {    Log.w(yzy, MyLayoutFirst->onInterceptTouchEvent->+MyUtils.getActionName(ev));    return super.onInterceptTouchEvent(ev);  }    @Override  public boolean onTouchEvent(MotionEvent event)  {    Log.e(yzy, MyLayoutFirst->onTouchEvent->+MyUtils.getActionName(event));    return super.onTouchEvent(event);  }    @Override  public boolean dispatchTouchEvent(MotionEvent ev)  {    Log.i(yzy, MyLayoutFirst->dispatchTouchEvent->+MyUtils.getActionName(ev));    return super.dispatchTouchEvent(ev);  }  }

自訂一個類;MyLayoutSecond.java

 

 

public class MyLayoutSecond extends LinearLayout{  private static final String TAG = MyLayoutSecond;  public MyLayoutSecond(Context context, AttributeSet attrs)  {    super(context, attrs);  }    @Override  public boolean onTouchEvent(MotionEvent event)  {    Log.e(yzy, MyLayoutSecond->MyLayoutSecond->+MyUtils.getActionName(event));    return super.onTouchEvent(event);  }    @Override  public boolean onInterceptTouchEvent(MotionEvent ev)  {    Log.w(yzy, MyLayoutSecond->onInterceptTouchEvent->+MyUtils.getActionName(ev));    return super.onInterceptTouchEvent(ev);  }    @Override  public boolean dispatchTouchEvent(MotionEvent ev)  {    Log.i(yzy, MyLayoutSecond->dispatchTouchEvent->+MyUtils.getActionName(ev));    return super.dispatchTouchEvent(ev);  } }

加入到main_layout.xml中

 

 

                            

MainActivity中加入onTouchEvent方法

 

 

public class MainActivity extends Activity{  @Override  protected void onCreate(Bundle savedInstanceState)  {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);  }  @Override  public boolean onCreateOptionsMenu(Menu menu)  {    // Inflate the menu; this adds items to the action bar if it is present.    getMenuInflater().inflate(R.menu.main, menu);    return true;  }    @Override  public boolean dispatchTouchEvent(MotionEvent ev)  {    Log.i(yzy, MainActivity->dispatchTouchEvent->+MyUtils.getActionName(ev));    return super.dispatchTouchEvent(ev);  }    @Override  public boolean onTouchEvent(MotionEvent event)  {    Log.e(yzy, MainActivity->onTouchEvent->+MyUtils.getActionName(event));    return super.onTouchEvent(event);  }}

最後就一個工具類,用來將事件id轉換為字串。

 

 

public class MyUtils{  private static final String TAG = MyUtils;  public static String getActionName(MotionEvent event)  {    String name=;    switch(event.getAction())    {      case MotionEvent.ACTION_DOWN:        name=ACTION_DOWN;        break;      case MotionEvent.ACTION_MOVE:        name=ACTION_MOVE;        break;      case MotionEvent.ACTION_UP:        name=ACTION_UP;        break;    }    return name;  }}

運行效果

 

 

其中藍色部分是MyLayoutSecond.java ,紅色部分是MyLayoutFirst.java
現在我點擊一下藍色部分:運行結果

可以看出,事件最先被Activity捕獲,然後分發給 MyLayoutFirst,MyLayoutFirst首先調用自身的onInterceptTouchEvent判斷是否將該事件攔截,由於預設返回是false,所以沒有攔截,從而事件分發給了MyLayoutSecond,MyLayoutSecond同樣通過dispatchTouchEvent分發出去,分發出去之前同樣檢查是否被攔截,預設都是沒有被攔截的,但是由於MyLayoutSecond是沒有子視圖的,所有最終事件有自己處理,調用自身的onTouchEvent方法,由於該方法預設返回的是false,所以認為此事件是沒有被消費掉的,繼續傳遞到了MyLayoutFirst中,同樣也沒有消費這個事件,最終傳遞到了Mainactivity,繼續往後看發現後面的ACTION_MOVE和ACTION_UP並沒有傳入MyLayoutFirst和MyLayoutSecond,這是因為一旦某一個事件沒有被處理,後面的事件是不會被分發的。所以ACTION_MOVE和ACTION_UP直接被MainActivity處理掉了。

下面再看第二種情況:

 

 

MainActivity

MyLayoutFirst

MyLayoutSecond

dispatchTouchEvent

super.dispatchTouchEvent

super.dispatchTouchEvent

super.dispatchTouchEvent

onInterceptTouchEvent

--

true

super.onInterceptTouchEvent(ev)

onTouchEvent

super.onTouchEvent

super.onTouchEvent

super.onTouchEvent

運行結果如下:

 

可以看出,事件傳遞到了MyLayoutFirst後沒有分發到MyLayoutSecond,直接調用自身的onTouchEvent,由於返回的是false,導致事件沒有消費,最終傳遞給了MainActivity,
而且後續事件也沒有傳遞到MyLayoutFirst和MyLayoutSecond,直接被MainActivity處理

 

第三種情況:

 

MainActivity

MyLayoutFirst

MyLayoutSecond

dispatchTouchEvent

super.dispatchTouchEvent

super.dispatchTouchEvent

super.dispatchTouchEvent

onInterceptTouchEvent

--

true

super.onInterceptTouchEvent(ev)

onTouchEvent

super.onTouchEvent

true

super.onTouchEvent

運行結果:

 

和情況二不同的是MyLayoutFirst的onTouchEvent返回了true,也就是說MyLayoutFirst消費了此事件,所以ACTION_DOWN也沒有再傳給MainActivity,並且ACTION_MOVE和ACTION_UP
均傳給了MyLayoutFirst

 

第四中情況:

 

MainActivity

MyLayoutFirst

MyLayoutSecond

dispatchTouchEvent

super.dispatchTouchEvent

super.dispatchTouchEvent

super.dispatchTouchEvent

onInterceptTouchEvent

--

super.onInterceptTouchEvent(ev)

super.onInterceptTouchEvent(ev)

onTouchEvent

super.onTouchEvent

super.onTouchEven

true

運行結果:

 

發現所有的事件都是傳遞到了MyLayoutSecond後被消費了

 

其實還有很多其他組合方式,大家如果又興趣可以自己嘗試改變每個函數的傳回值,查看列印結果,這裡我就不一一列舉了。。。。。


最後我會提供一個小demo示範如何解決滑動衝突,背景如下:
一個ViewPager裡麵包含兩個Framgent,有一個Fragment裡面有一個HorizontalListView ,如何滑動衝突?
我就貼出關鍵代碼吧

 

 

horizontal=(HorizontalListView)view.findViewById(R.id.hscroll);    horizontal.setOnTouchListener(new OnTouchListener()    {            @Override      public boolean onTouch(View arg0, MotionEvent event)      {        if(event.getAction()==MotionEvent.ACTION_DOWN)        {          parent.requestDisallowInterceptTouchEvent(true);        }else if(event.getAction()==MotionEvent.ACTION_UP)        {          parent.requestDisallowInterceptTouchEvent(false);        }        return false;      }    });

加入這段代碼就可以避免滑動衝突了,至於為什麼大家可以參考我的前以前文章《Android Touch 事件傳遞機制詳解 上》 這兩個demo的例子我均會上傳下載的

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.