Android手勢操作
前言
利用手勢操作在現在的APP中越來越普及,大多數時候使用Fling,Scroll等Gesture能大幅度提高用戶的操作體驗,特別是大屏手機返回鍵程越來越大的現狀下。
在Android系統下,手勢識別是通過GestureDetector.OnGestureListener接口實現的,不過官方的文檔可能覺得這部分
太基礎和簡單了,所以官方的API文檔中對手勢的講解描述的都很簡單,API
Demo中也沒有提供一個清楚的例子,所以自己總結一下,其中還是涉及不少的基礎知識和一些官方文檔中說明不清的地方,如果不能好好掌握這些基礎知識,做
起事情來難免要吃一些苦頭。言歸正傳,下面我們開始:
基礎知識
我們先來明確一些概念,首先,Android的事件處理機制是基于Listener(監聽器)來實現的,比我們今天所說的觸摸屏相關的事件,就是通 過onTouchListener。其次,所有View的子類都可以通過setOnTouchListener()、 setOnKeyListener()等方法來添加對某一類事件的監聽器。第三,Listener一般會以Interface(接口)的方式來提供,其中 包含一個或多個abstract(抽象)方法,我們需要實現這些方法來完成onTouch()、onKey()等等的操作。這樣,當我們給某個view設 置了事件Listener,并實現了其中的抽象方法以后,程序便可以在特定的事件被dispatch到該view的時候,通過callbakc函數給予適 當的響應。
這篇文章簡單介紹了事件觸發的過程:Android事件分發圖解
實作
我們現在實作一個使用手勢的例子。
我們給RelativeView的實例my_view設定了一個onTouchListener,因為GestureTest類實現了
OnTouchListener
接口,所以簡單的給一個this作為參數即可。onTouch方法則是實現了OnTouchListener中的抽象方法,我們只要在這里添加邏輯代碼即
可在用戶觸摸屏幕時做出響應,
public class MainActivity extends ActionBarActivity implements View.OnTouchListener,GestureDetector.OnGestureListener{ GestureDetector gestureDetector = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); gestureDetector = new GestureDetector(this); gestureDetector.setIsLongpressEnabled(true); View v = findViewById(R.id.my_view); v.setOnTouchListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } @Override public boolean onTouch(View view, MotionEvent motionEvent) { Log.i("HYY","onTouch present"); return gestureDetector.onTouchEvent(motionEvent); } @Override public boolean onDown(MotionEvent motionEvent) { Log.i("HYY","onDown present"); return true; } @Override public void onShowPress(MotionEvent motionEvent) { Log.i("HYY","onShowPress present"); } @Override public boolean onSingleTapUp(MotionEvent motionEvent) { Log.i("HYY","onSingleTapUp present"); return false; } @Override public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent2, float v, float v2) { Log.i("HYY","onScroll present"); return false; } @Override public void onLongPress(MotionEvent motionEvent) { Log.i("HYY","onLongPress present"); } @Override public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent2, float v, float v2) { Log.i("HYY","onFling present"); return false; } }
特別提示
這里有一點需要特別注意:要觸發onScroll和onFling,必須讓監聽器的onDown的返回值設為true
那么為什么如果不把onDown的返回值設為true的話,onScroll和onFiling就都不會被觸發呢?我們來看一下源碼中的介紹
/** * Notified when a scroll occurs with the initial on down {@link MotionEvent} and the * current move {@link MotionEvent}. The distance in x and y is also supplied for * convenience. * * @param e1 The first down motion event that started the scrolling. * @param e2 The move motion event that triggered the current onScroll. * @param distanceX The distance along the X axis that has been scrolled since the last * call to onScroll. This is NOT the distance between {@code e1} * and {@code e2}. * @param distanceY The distance along the Y axis that has been scrolled since the last * call to onScroll. This is NOT the distance between {@code e1} * and {@code e2}. * @return true if the event is consumed, else false */ boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY); /** * Notified of a fling event when it occurs with the initial on down {@link MotionEvent} * and the matching up {@link MotionEvent}. The calculated velocity is supplied along * the x and y axis in pixels per second. * * @param e1 The first down motion event that started the fling. * @param e2 The move motion event that triggered the current onFling. * @param velocityX The velocity of this fling measured in pixels per second * along the x axis. * @param velocityY The velocity of this fling measured in pixels per second * along the y axis. * @return true if the event is consumed, else false */ boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
onScroll和onFling方法的注釋上寫的很清楚,要判定為onScroll或onFling必須要建立在onDown被消費的前提下(即onDown返回true)。
來自:http://blog.csdn.net/yuyuanhuang/article/details/45068619