android事件處理機制

來源:互聯網
上載者:User

android事件處理機制

  談到android事件處理,最複雜的就是對Touch事件的處理,因為Touch事件包括:down, move, up, cancle和多點觸摸等多種情況,多點觸摸的情況先不討論,因為Touch有這麼多的狀態,所以Touch相對來說是最難處理的,下面就來討論一下android系統是如何處理Touch事件的.

  1.說到事件處理,首先我們要明白,為什麼要處理事件,要瞭解android系統本身對事件的一個處理過程.在實際的開發中,我們如果都用系統的基本控制項,那是不需要去處理事件的,但是如果我們用複雜的布局嵌套去做一些特殊的需求,例如:ScrollView中嵌套ListView,ScrollView嵌套ViewPager等,則會產生事件衝突,所以,由於事件衝突的存在,我們要去處理這些衝突,只有瞭解android的事件處理機制,才能有效去處理事件衝突.還有就是如果我們要新開發一個組件,則組件的所有事件都要我們自己去做處理,這種情況也需要我們去處理事件.所以:由於存在以上說到的兩種情況,我們要自己處理事件.

  2.有了處理事件的動機後,接下來就要瞭解android系統本身是如何處理複雜的事件的.android系統為所有的事件提供了三個相關的方法,以下只以Touch事件為例說明.

這三個方法分別是:

   dispatchTouchEvent(MotionEvent ev);  (Activity, ViewGroup, View都有此方法)

onInterceptTouchEvent(MotionEvent ev); (只有ViewGroup有)

onTouchEvent(MotionEvent);      (Activity, ViewGroup, View都有此方法)

要想瞭解android系統是如何對事件進行一步一步的處理,這三個方法是必須要掌握的.其中:dispatchTouchEvent(MotionEvent ev);方法是用來對事件進行分發的,即將事件分發到目標控制項,onInterceptTouchEvent(MotionEvent ev)是用來過濾事件的,即進行事件的攔截,也就是是否要向下傳遞事件,onTouchEvent(MotionEvent ev)才是最終用來處理事件的,也就是說我們平常重寫onTouchEvent時,其實,系統已經預設幫我們調用了前兩個方法.下面就來詳細分析一下三個方法.

  首先要提的是,android系統對本件的處理是一層一層向下傳遞處理(樹形處理).那這棵樹是從那來的呢..就是我們的布局樹,一個布局,無論是代碼編寫的布局還是xml產生的布局,android系統對它進行解析時都是將其組裝成一棵UI樹,最外層布局是整個UI樹的根.知道這個以後,再來分析事件的處理.

  處理流程:當我們的手指觸摸到手機螢幕時,當前處於onStart()狀態的Activity最先接收到此Touch事件下的ACTON_DOWN,然後開始調用它自己dispatchTouchEvent()開始進行DOWN事件分發,如果此方法返回true,則Activity不向下分發事件,則整個布局都不會收到DOWN事件,TouchEvent直接到Activity的onTouchEvent()方法進行事件處理.如果返回false,則表示DOWN是要被分發到下層的,此時DOWN事件被直接分發(因為沒有過濾方法)到UI樹的根布局(即最外層的布局),根布局拿到DOWN事件時,執行自己的dispatchTouchEvent方法,返回true,則事件直接交到根布局的onTouchEvent()中進行處理,false則表示還得向下分發,此時事件被傳遞到根布局的onInterceptTouchEvent()方法中,如果此方法返回true,表示要對此事件進行過濾,則此DOWN事件又直接進行到根布局的onTouchEvent()方法直接處理,false則,要根布局不對事件進行過濾,DOWN事件繼續向下傳遞,直到達到目標組件後,目標組件調用自己的dispatchTouchEvent()方法,由於是目標組件,直接分發事件到自己的onTouchEvent方法中,目標組件如果處理完這個DOWN事件後返回true,表示該事件被消費完畢,不再向上層傳遞,如果返回false,則表示沒有消費完這個DOWN事件,DOWN向上傳遞到自己的父組件中,父組件再進行DOWN事件的處理.一直向上傳遞直到事件被扔到虛擬機器.DOWN事件才算處理完成,接著調用MOVE,MOVE完了UP,整個流程與DOWN是一樣的.

這裡要強調一點的是:如果一個組件沒有接收到DOWN事件,那麼一定接收不到MOVE,UP事件。


通過以上的流程,我們可以明白:android系統對任何一個事件的處理都是這樣的,分發事件,過濾事件,處理事件,下一個事件, 分發事件,過濾事件,處理事件……一直這樣迴圈去處理所有的事件的。即:事件的分發,過濾是從根到葉的,處理則是從葉再到根的。

下面是我將上面的文字流程畫的一張處理流程圖:


從圖上看,我們可以更直觀的感受整個Touch事件的處理流。


<喎?http://www.bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+ICAgICAgMy69ssHLYW5kcm9pZM+1zbPKx8jnus60psDtysK8/rXE1fu49sH3s8yjrMTHztLDx8q1vMq5pNf31tDI57rOyKW0psDtysK8/sTYoa2hrc/Cw+a9q87S1q7HsLSmwO25/bXE0ru49sD919PAtLfWzvahozwvcD4KPHA+ICAgICAgytfPyM7Sw8e007j5tb3StsiltKbA7crCvP6jrLT6wuvI58/Co7o8L3A+CjxwPiAgICAgIDxwcmUgY2xhc3M9"brush:java;">package com.micen.buyers.view.category;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.widget.ScrollView;import com.micen.buyers.util.Util;public class MyScrollView extends ScrollView {private float mLastMotionY;private float mLastMotionX;public MyScrollView(Context context, AttributeSet attrs) {super(context, attrs);// TODO Auto-generated constructor stub}/** * 通過重寫此方法,達到對事件的處理 */@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {// TODO Auto-generated method stubfinal float x = ev.getX();final float y = ev.getY();switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:mLastMotionX = x;mLastMotionY = y;break;case MotionEvent.ACTION_MOVE:if (Math.abs(y - mLastMotionY) > Util.dip2px(20)&& Math.abs(x - mLastMotionX) < Util.dip2px(5)) {return true; // 如果MOVE事件的縱座標超過20px, 橫向小於5dp// 則認為是滑動scrollview,返回true,則事件不向下分發,直接傳入到// onTouchEvent方法中,否則,認為滑動事件不屬於scrollview處理,允許分發}break;case MotionEvent.ACTION_UP:break;case MotionEvent.ACTION_CANCEL:break;}return super.dispatchTouchEvent(ev);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {// TODO Auto-generated method stubreturn super.onInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent ev) {Log.e("--------->", "user want to scroll");return super.onTouchEvent(ev);}}上述代碼,我們是重寫了ScrollView的dispatchTouchEvent()達到對事件的一個特殊處理,如果滿足了我們的規則,則直接到onTouchEvent()中處理,否則,事件被發送到 onInterceptTouchEvent()中執行過濾,由於此方法中沒有過濾,則下發傳遞事件.

同樣的效果,我們從葉子開始處理事件衝突,代碼如下:

package com.micen.buyers.view.category;import android.content.Context;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.view.MotionEvent;import com.micen.buyers.util.Util;public class MyViewPager extends ViewPager{private boolean flag = true;private float mLastMotionY;private float mLastMotionX;public MyViewPager(Context context){super(context);}public MyViewPager(Context context, AttributeSet attrs){super(context, attrs);        }@Overridepublic boolean dispatchTouchEvent(MotionEvent ev){final float x = ev.getX();final float y = ev.getY();switch (ev.getAction()){case MotionEvent.ACTION_DOWN:setPullToScrollViewStatus(true); //先預設父控制項不接收滑動事件,事件直接傳遞到子滑動組件flag = true;mLastMotionX = x;mLastMotionY = y;mHandler.sendEmptyMessage(1);break;case MotionEvent.ACTION_MOVE:if (flag){if (Math.abs(y - mLastMotionY) > Util.dip2px(20) && Math.abs(x - mLastMotionX) < Util.dip2px(5)){flag = false;setPullToScrollViewStatus(false); //滿足條件,父滑動控制項將事件過濾掉了,不再傳到ViewPager中了.}}break;case MotionEvent.ACTION_UP:setPullToScrollViewStatus(false);case MotionEvent.ACTION_CANCEL:setPullToScrollViewStatus(false);break;}return super.dispatchTouchEvent(ev);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent event){return super.onInterceptTouchEvent(event);}@Overridepublic boolean onTouchEvent(MotionEvent event){return super.onTouchEvent(event);}private void setPullToScrollViewStatus(boolean disallowIntercept){//調用父控制項的requestDisallowInterceptTouchEvent()方法,傳入true,則等將於父控制項的onTInterceptTouchEvent返回false,//不過濾,否則,父控制項過濾掉事件,不再向下傳遞.getParent().getParent().requestDisallowInterceptTouchEvent(disallowIntercept);}}

總結:android事件處理流程,是每一個搞android的人應該熟練掌握的.


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.