手機屏幕事件的處理方法onTouchEvent。該方法在View類中的定義,並且所有的View子類全部重寫了該方法,應用程序可以通過該方法處理手機屏幕的觸摸事件。該方法的簽名如下所示。
- public boolean onTouchEvent(MotionEvent event)
參數event:參數event爲手機屏幕觸摸事件封裝類的對象,其中封裝了該事件的所有信息,例如觸摸的位置、觸摸的類型以及觸摸的時間等。該對象會在用戶觸摸手機屏幕時被創建。
返回值:該方法的返回值機理與鍵盤響應事件的相同,同樣是當已經完整地處理了該事件且不希望其他回調方法再次處理時返回true,否則返回false。
該方法並不像之前介紹過的方法只處理一種事件,一般情況下以下三種情況的事件全部由onTouchEvent方法處理,只是三種情況中的動作值不同。
屏幕被按下:當屏幕被按下時,會自動調用該方法來處理事件,此時MotionEvent.getAction()的值爲MotionEvent.ACTION_DOWN,如果在應用程序中需要處理屏幕被按下的事件,只需重新該回調方法,然後在方法中進行動作的判斷即可。
屏幕被擡起:當觸控筆離開屏幕時觸發的事件,該事件同樣需要onTouchEvent方法來捕捉,然後在方法中進行動作判斷。當MotionEvent.getAction()的值爲MotionEvent.ACTION_UP時,表示是屏幕被擡起的事件。
在屏幕中拖動:該方法還負責處理觸控筆在屏幕上滑動的事件,同樣是調用MotionEvent.getAction()方法來判斷動作值是否爲MotionEvent.ACTION_MOVE再進行處理。
Android Touch Screen 與傳統Click Touch Screen不同,會有一些手勢(Gesture),例如Fling,Scroll等等。這些Gesture會使用戶體驗大大提升。
Android中的Gesture識別(detector)是通過GestureDetector.OnGestureListener接口實現的。
首先,Android事件處理機制是基於Listener實現的,比如觸摸屏相關的事件,就是通過onTouchListener實現;
其次,所有View的子類都可以通過setOnTouchListener()、setOnKeyListener()等方法來添加對某一類事件的Listener;
第三,Listener一般會以Interface的方式來提供,其中包含一個或多個abstract方法,我們需要實現這些方法來完成 onTouch()、onKey()等操作。這樣,程序便可以在特定的事件被dispatch到該view的時候,通過callback函數給予適當的響 應。
1. Touch Screen Click舉例
- public class MyGesture extends Activity implements OnTouchListener
- {
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- TextView tv = (TextView) findViewById(R.id.tv);
- tv.setOnTouchListener(this);
- }
- public boolean onTouch(View v, MotionEvent event)
- {
- Toast.makeText(this, "Touch Touch", Toast.LENGTH_SHORT).show();
- return false;
- }
- }
我們可以通過MotionEvent的getAction()方法來獲取Touch事件的類型,包括 ACTION_DOWN(按下觸摸屏), ACTION_MOVE(按下觸摸屏後移動受力點), ACTION_UP(鬆開觸摸屏)和ACTION_CANCEL(不會由用戶直接觸發)。藉助對於用戶不同操作的判斷,結合getRawX()、 getRawY()、getX()和getY()等方法來獲取座標後,我們可以實現諸如拖動某一個按鈕,拖動滾動條等功能。2. 當我們捕捉到Touch操作的時候,如何識別出用戶的Gesture?這裏我們需要GestureDetector.OnGestureListener接口的幫助,代碼如下:
- public class MyGesture extends Activity implements OnTouchListener,
- OnGestureListener
- {
- private GestureDetector mGestureDetector;
- public MyGesture()
- {
- mGestureDetector = new GestureDetector(this);
- }
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- TextView tv = (TextView) findViewById(R.id.tv);
- tv.setOnTouchListener(this);
- tv.setFocusable(true);
- tv.setClickable(true);
- tv.setLongClickable(true);
- mGestureDetector.setIsLongpressEnabled(true);
- }
- /*
- * *在onTouch()方法中,我們調用GestureDetector的onTouchEvent()方法,
- * 將捕捉到的MotionEvent交給GestureDetector * 來分析是否有合適的callback函數來處理用戶的手勢
- */
- public boolean onTouch(View v, MotionEvent event)
- {
- return mGestureDetector.onTouchEvent(event);
- }
- // 用戶輕觸觸摸屏,由1個MotionEvent ACTION_DOWN觸發
- public boolean onDown(MotionEvent arg0)
- {
- Log.i("MyGesture", "onDown");
- Toast.makeText(this, "onDown", Toast.LENGTH_SHORT).show();
- return true;
- }
- /*
- * * 用戶輕觸觸摸屏,尚未鬆開或拖動,由一個1個MotionEvent ACTION_DOWN觸發 *
- * 注意和onDown()的區別,強調的是沒有鬆開或者拖動的狀態
- */
- public void onShowPress(MotionEvent e)
- {
- Log.i("MyGesture", "onShowPress");
- Toast.makeText(this, "onShowPress", Toast.LENGTH_SHORT).show();
- }
- // 用戶(輕觸觸摸屏後)鬆開,由一個1個MotionEvent ACTION_UP觸發
- public boolean onSingleTapUp(MotionEvent e)
- {
- Log.i("MyGesture", "onSingleTapUp");
- Toast.makeText(this, "onSingleTapUp", Toast.LENGTH_SHORT).show();
- return true;
- }
- // 用戶按下觸摸屏、快速移動後鬆開,由1個MotionEvent ACTION_DOWN, 多個ACTION_MOVE, 1個ACTION_UP觸發
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY)
- {
- Log.i("MyGesture", "onFling");
- Toast.makeText(this, "onFling", Toast.LENGTH_LONG).show();
- return true;
- }
- // 用戶按下觸摸屏,並拖動,由1個MotionEvent ACTION_DOWN, 多個ACTION_MOVE觸發
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
- float distanceY)
- {
- Log.i("MyGesture", "onScroll");
- Toast.makeText(this, "onScroll", Toast.LENGTH_LONG).show();
- return true;
- }
- // 用戶長按觸摸屏,由多個MotionEvent ACTION_DOWN觸發
- public void onLongPress(MotionEvent e)
- {
- Log.i("MyGesture", "onLongPress");
- Toast.makeText(this, "onLongPress", Toast.LENGTH_LONG).show();
- }
- }
3. Fling事件的處理代碼:除了第一個觸發Fling的ACTION_DOWN和最後一個ACTION_MOVE中包含的座標等信息外,我們還可以根據用 戶在X軸或者Y軸上的移動速度作爲條件。比如下面的代碼中我們就在用戶移動超過100個像素,且X軸上每秒的移動速度大於200像素時才進行處理。
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY)
- {
- // 參數解釋:
- // e1:第1個ACTION_DOWN MotionEvent
- // e2:最後一個ACTION_MOVE MotionEvent
- // velocityX:X軸上的移動速度,像素/秒
- // velocityY:Y軸上的移動速度,像素/秒
- // 觸發條件 :
- // X軸的座標位移大於FLING_MIN_DISTANCE,且移動速度大於FLING_MIN_VELOCITY個像素/秒
- final int FLING_MIN_DISTANCE = 100, FLING_MIN_VELOCITY = 200;
- if (e1.getX() - e2.getX() > FLING_MIN_DISTANCE
- && Math.abs(velocityX) > FLING_MIN_VELOCITY)
- {
- // Fling left
- Log.i("MyGesture", "Fling left");
- Toast.makeText(this, "Fling Left", Toast.LENGTH_SHORT).show();
- }
- else if (e2.getX() - e1.getX() > FLING_MIN_DISTANCE
- && Math.abs(velocityX) > FLING_MIN_VELOCITY)
- {
- // Fling right
- Log.i("MyGesture", "Fling right");
- Toast.makeText(this, "Fling Right", Toast.LENGTH_SHORT).show();
- }
- return false;
- }
這個例子中,tv.setLongClickable(true)是必須的,因爲 只有這樣,view才能夠處理不同於Tap(輕觸)的hold(即ACTION_MOVE,或者多個ACTION_DOWN),我們同樣可以通過layout定義中的android:longClickable來做到這一點.