Android開發 Android手勢

之前做的App是完全沒有任何手勢支持的,對於現在的程序來說,如果沒有一些手勢的支持,感覺實在是有點落後了,支持手勢的App才叫cool。於是在這次重新搭建ifood for android框架的同時下決心讓自己的App完全支持手勢。下面就來看下自己實現的一個全局滑動切換窗口的例子。

在android系統中,手勢的識別是通過 GestureDetector.OnGestureListener接口來實現的。如果要自定義手勢需要重寫這個接口裏的一些方法,廢話不多說,下面上代碼:

自定義的一個GestureLisntener:

MyGestureListener.java
public class MyGestureListener implements OnGestureListener {

	static final String TAG = "MyGestureListener";

	private static final int SWIPE_MAX_OFF_PATH = 100;
	private static final int SWIPE_MIN_DISTANCE = 100;
	private static final int SWIPE_THRESHOLD_VELOCITY = 100;
	
	public Context context;
	
	public MyGestureListener(Context context) {
		this.context = context;
	}

	@Override
	public boolean onDown(MotionEvent e) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void onShowPress(MotionEvent e) {
		// TODO Auto-generated method stub
		Log.e(TAG, "onShowPress");
	}

	@Override
	public boolean onSingleTapUp(MotionEvent e) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
			float distanceY) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void onLongPress(MotionEvent e) {
		// TODO Auto-generated method stub
		Log.e(TAG, "onLongPress");
	}

	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
			float velocityY) {
		if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
			return false;

		if ((e1.getX() - e2.getX()) > SWIPE_MIN_DISTANCE
				&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
			Log.e(TAG, "onFling left");

		} else if ((e2.getX() - e1.getX()) > SWIPE_MIN_DISTANCE
				&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
			Log.e(TAG, "onFling right");
			((Activity) context).finish();
			
		}
		return true;
	}

}

在這個類中的onFling()方法中從左向右滑動時實現了界面的切換,如果有更復雜的手勢支持,同樣可以在這個基類中進行添加。

接下來新建一個GestureActivity實現Gesture滑動切換界面,讓支持手勢的Activity繼承它,這樣就繼承了它的手勢支持功能,提高代碼複用。

GestureActivity.java
public class GestureActivity extends ActivityBase {

	MyGestureListener listener = new MyGestureListener(this);
	protected GestureDetector gestureDetector = new GestureDetector(listener);
	
	public boolean onTouchEvent(MotionEvent event) {
        if (gestureDetector.onTouchEvent(event))
            return true;
        else  
            return false;
    }
	
}

這樣就實現了一個簡單的滑動切換頁面的框架,如果想支持更多的手勢,只需要重寫MyGestureListener的方法就可以了。

不過不要高興的太早,在一般的Activity手勢支持是正常的,可是碰到一些包含ScrollView或者ListView的Activity時,手勢就不相應了。原因是因爲這些滑動的組件本身就已經具有了手勢的支持,這樣就會產生了衝突,導致自定義的手勢沒有被識別到。google了很久,似乎也沒個具體的方法,後來看到說用dispatchTouchEvent(MotionEvent ev) 的方法,果然可以。於是在GestureActivity裏就多了這樣一個方法:

public boolean dispatchTouchEvent(MotionEvent ev) {
    gestureDetector.onTouchEvent(ev);
    return super.dispatchTouchEvent(ev);
}

此時再試一下,果然所有Activity都實現了自定義的手勢事件。但是爲什麼加上這個方法就可以了呢,必須要搞明白。

android中的事件類型分爲按鍵事件和屏幕觸摸事件,Touch事件是屏幕觸摸事件的基礎事件,有必要對它進行深入的瞭解。

一個最簡單的屏幕觸摸動作觸發了一系列Touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE…->ACTION_MOVE->ACTION_UP

當屏幕中包含一個ViewGroup,而這個ViewGroup又包含一個子view,這個時候android系統如何處理Touch事件呢?到底是ViewGroup來處理Touch事件,還是子view來處理Touch事件呢?答案是:不一定。

android系統中的每個View的子類都具有下面三個和TouchEvent處理密切相關的方法:

1.public boolean dispatchTouchEvent(MotionEvent ev) 這個方法用來分發TouchEvent

2.public boolean onInterceptTouchEvent(MotionEvent ev) 這個方法用來攔截TouchEvent

3.public boolean onTouchEvent(MotionEvent ev) 這個方法用來處理TouchEvent

當TouchEvent發生時,首先Activity將TouchEvent傳遞給最頂層的View, TouchEvent最先到達最頂層 view 的 dispatchTouchEvent ,然後由 dispatchTouchEvent 方法進行分發,如果dispatchTouchEvent返回true ,則交給這個view的onTouchEvent處理,如果dispatchTouchEvent返回 false ,則交給這個 view 的 interceptTouchEvent 方法來決定是否要攔截這個事件,如果 interceptTouchEvent 返回 true ,也就是攔截掉了,則交給它的 onTouchEvent 來處理,如果 interceptTouchEvent 返回 false ,那麼就傳遞給子 view ,由子 view 的 dispatchTouchEvent 再來開始這個事件的分發。如果事件傳遞到某一層的子 view 的 onTouchEvent 上了,這個方法返回了 false ,那麼這個事件會從這個 view 往上傳遞,都是 onTouchEvent 來接收。而如果傳遞到最上面的 onTouchEvent 也返回 false 的話,這個事件就會“消失”,而且接收不到下一次事件。

看到這終於清楚了上面的疑問,dispatchTouchEvent()方法直接將觸摸事件交給了gestureDetector的觸摸事件,這樣就解決了衝突問題。

發佈了17 篇原創文章 · 獲贊 18 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章