Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android自定義控件系列教程-----touch事件的傳遞

android自定義控件系列教程-----touch事件的傳遞

編輯:關於Android編程

前沿:

很久沒有寫過博客了,因為工作的原因很少有時間寫東西了,最近想寫一個UI系列的博客,因為我發現這一系列的都很少,而且沒有那麼系統,這裡我想以我自己的觀點來闡述一下如何自定義android 控件系列。

自定義控件闡述:

在我的理解裡面自定義控件,需要了解到touch事件的傳遞、分發、攔截機制,Scroller類的運用,andorid 視圖的理解,ViewGroup的熟悉,因為我們絕大多的控件都是繼承自ViewGroup,還有就是要學會布局測量等。

Touch事件的傳遞

首先我們要了解在android系統裡面有幾個地方會走touch事件,這個是老生常談的問題了,但是我還是希望寫一下這個問題,因為溫故而知新嘛,我們首先得知道VIew類這種不能作為容器的類只會有這兩個函數:
	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		return super.dispatchTouchEvent(event);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		return super.onTouchEvent(event);
	}
而能做為容器的類如ViewGroup以及繼承它的類會有這幾個函數:
@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		// TODO Auto-generated method stub
		return super.onInterceptTouchEvent(ev);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		return super.onTouchEvent(event);
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		// TODO Auto-generated method stub
		return super.dispatchTouchEvent(ev);
	}
現在我們就分別來重寫這幾個函數分別走一遍流程,讓我們更能清楚的看到android的touch事件是怎麼傳遞的。我們來重寫一下這兩類的方法。重寫一個TextView
public class MyTextView extends TextView{
	private final String TAG = MyTextView.class.getSimpleName();

	public MyTextView(Context context) {
		super(context);
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			Log.d(TAG, TAG + "dispatchTouchEvent+ACTION_DOWN");
			break;
		case MotionEvent.ACTION_POINTER_DOWN:
			Log.d(TAG, TAG + "dispatchTouchEvent+ACTION_POINTER_DOWN");
			break;
		case MotionEvent.ACTION_POINTER_UP:
			Log.d(TAG, TAG + "dispatchTouchEvent+ACTION_POINTER_UP");
			break;
		case MotionEvent.ACTION_MOVE:
			Log.d(TAG, TAG + "dispatchTouchEvent+ACTION_MOVE");
			break;
		case MotionEvent.ACTION_UP:
			Log.d(TAG, TAG + "dispatchTouchEvent+ACTION_UP");
			break;
		}
		return super.dispatchTouchEvent(event);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			Log.d(TAG, TAG + "onTouchEvent+ACTION_DOWN");
			break;
		case MotionEvent.ACTION_POINTER_DOWN:
			Log.d(TAG, TAG + "onTouchEvent+ACTION_POINTER_DOWN");
			break;
		case MotionEvent.ACTION_POINTER_UP:
			Log.d(TAG, TAG + "onTouchEvent+ACTION_POINTER_UP");
			break;
		case MotionEvent.ACTION_MOVE:
			Log.d(TAG, TAG + "onTouchEvent+ACTION_MOVE");
			break;
		case MotionEvent.ACTION_UP:
			Log.d(TAG, TAG + "onTouchEvent+ACTION_UP");
			break;
		}
		return super.onTouchEvent(event);
	}
}
然後我們再重寫一個LinearLayout
public class MyLinearLayout extends LinearLayout {
	private final String TAG = MyLinearLayout.class.getSimpleName();

	public MyLinearLayout(Context context) {
		super(context);
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			Log.d(TAG, TAG + "onInterceptTouchEvent+ACTION_DOWN");
			break;
		case MotionEvent.ACTION_POINTER_DOWN:
			Log.d(TAG, TAG + "onInterceptTouchEvent+ACTION_POINTER_DOWN");
			break;
		case MotionEvent.ACTION_POINTER_UP:
			Log.d(TAG, TAG + "onInterceptTouchEvent+ACTION_POINTER_UP");
			break;
		case MotionEvent.ACTION_MOVE:
			Log.d(TAG, TAG + "onInterceptTouchEvent+ACTION_MOVE");
			break;
		case MotionEvent.ACTION_UP:
			Log.d(TAG, TAG + "onInterceptTouchEvent+ACTION_UP");
			break;
		}
		return super.onInterceptTouchEvent(ev);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			Log.d(TAG, TAG + "onTouchEvent+ACTION_DOWN");
			break;
		case MotionEvent.ACTION_POINTER_DOWN:
			Log.d(TAG, TAG + "onTouchEvent+ACTION_POINTER_DOWN");
			break;
		case MotionEvent.ACTION_POINTER_UP:
			Log.d(TAG, TAG + "onTouchEvent+ACTION_POINTER_UP");
			break;
		case MotionEvent.ACTION_MOVE:
			Log.d(TAG, TAG + "onTouchEvent+ACTION_MOVE");
			break;
		case MotionEvent.ACTION_UP:
			Log.d(TAG, TAG + "onTouchEvent+ACTION_UP");
			break;
		}
		return super.onTouchEvent(event);
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			Log.d(TAG, TAG + "dispatchTouchEvent+ACTION_DOWN");
			break;
		case MotionEvent.ACTION_POINTER_DOWN:
			Log.d(TAG, TAG + "dispatchTouchEvent+ACTION_POINTER_DOWN");
			break;
		case MotionEvent.ACTION_POINTER_UP:
			Log.d(TAG, TAG + "dispatchTouchEvent+ACTION_POINTER_UP");
			break;
		case MotionEvent.ACTION_MOVE:
			Log.d(TAG, TAG + "dispatchTouchEvent+ACTION_MOVE");
			break;
		case MotionEvent.ACTION_UP:
			Log.d(TAG, TAG + "dispatchTouchEvent+ACTION_UP");
			break;
		}
		return super.dispatchTouchEvent(ev);
	}
}


public class TestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	MyLinearLayout layout = new MyLinearLayout(this);
	
	
	MyTextView myTextView = new MyTextView(this);
	myTextView.setText("touch event");
	
	layout.addView(myTextView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
	
	setContentView(layout);
}
}
我們來看看log \ 然後我們在把TextView改成Button來看一下然後在看一下log \ 分析上面的log我們看到,touch事件首先走到的是父親的dispatchTouchEvent方法中,然後是onInterceptTouchEvent過後才是MyTextView的dispatchTouchEvent和TouchEent中。所以我們知道了一件事: 那就是所有的touch事件一定是先傳遞給父親然後在傳遞給孩子,然後在分析函數執行的順序最開始執行的是dispatchTouchEvent方法,後面執行onInterceptTouchEvent最後才走到onTouchEvent事件當中。同時我們也要注意這幾個函數的的返回值是boolean變量。然後我們再把MyLinearLayout的dispatchTouchEvent方法的返回值返回true,跑一下。
\
你會看到事件始終都只在MyLinearLayout裡面了,根本就沒有傳遞到孩子裡面去了。同樣我們把它返回false,試試
\
這時候看到只有down事件了,這說明了什麼呢?當dispatchTouchEvent返回true的時候會繼續傳遞事件給自身控件dispatchTouchEvent處理,就像剛才的MylinearLayout一樣仍然可以執行,DOWN和UP事件,當我們返回了false就連自身控件都不能接收到事件了。同樣我們把dispatchTouchEvent還原,然後在onInterceptTouchEvent裡面返回true;

\ 可以看到事件也只分發到自身控件並進入到自身的OntouchEvent中,然後我們在把onInterceptTouchEvent的返回值改為false,看看結果
\
可以看到我們的事件沒有收到任何影響所有的都照常執行,同樣把MylinearLayout中的onInterceptTouchEvent復原,現在注意了我們要修改的是MyTextView中的onTouchEvent的返回值,我們把它修改為true
\
可以看到也沒有任何變化,我們在試試把它改為false。

可以看到MytextView只接收到DOWN事件就再也不會接收到其他事件了。

結論:

androidtouch事件的默認傳遞順序的父親控件到子控件,而函數的調用順序大致是這樣的dispatchTouchEvent---->消息分發--->onInterceptTouchEvent--->事件打斷-->onTouchEvent-->>事件處理。 關於返回值的問題我來簡單的總結一下剛才上面的實驗和結論: dispatchTouchEvent返回的是true的時候事件是不會繼續往下面傳遞了,一直都會走本身的dispatchTouchEvent這個方法,當返回為false的時候只會走一次dispatchTouchEvent這個方法的Down事件: onInterceptTouchEvent返回的是true的時候是把事件攔截了讓他走自身的onTouchEvent方法,當他返回為false的方法的時候不進行攔截正常進行。 onTouchEvent這個方法的返回值是true的時候,繼續分發事件到自身的touchEvent中,當為false的時候只會分發第一次down事件,還有各種返回值的組合我就不一一舉例了,要想寫好自定義的UI和控件touch事件的分發是必須得學好的,剩下的就慢慢的自己體會把。
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved