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來做到這一點。