Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android事件處理機制

android事件處理機制

編輯:關於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事件的處理流。


<喎?/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 } /** * 通過重寫此方法,達到對事件的處理 */ @Override public boolean dispatchTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub final 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); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub return super.onInterceptTouchEvent(ev); } @Override public 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);
        }

	@Override
	public 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);
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent event)
	{
		return super.onInterceptTouchEvent(event);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		return super.onTouchEvent(event);
	}

	
	private void setPullToScrollViewStatus(boolean disallowIntercept)
	{
		//調用父控件的requestDisallowInterceptTouchEvent()方法,傳入true,則等將於父控件的onTInterceptTouchEvent返回false,
		//不過濾,否則,父控件過濾掉事件,不再向下傳遞.
		getParent().getParent().requestDisallowInterceptTouchEvent(disallowIntercept);
	}
}

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


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved