GestureDetector和SimpleOnGestureListener的使用教程
原文:https://www.cnblogs.com/transmuse/archive/2010/12/2.html
1. 當用戶觸摸屏幕的時候,會產生許多手勢,例如down,up,scroll,filing等等,我們知道View類有個View.OnTouchListener內部接口,通過重寫他的onTouch(View v,MotionEvent event)方法,我們可以處理一些touch事件,但是這個方法太過簡單,如果需要處理一些複雜的手勢,用這個接口就會很麻煩(因為我們要自己根據用戶觸摸的軌跡去判斷是什麼手勢)Android sdk給我們提供了GestureDetector(Gesture:手勢Detector:識別)類,通過這個類我們可以識別很多的手勢,主要是通過他的onTouchEvent(event)方法完成了不同手勢的識別。雖然他能識別手勢,但是不同的手勢要怎麼處理,應該是提供給程序員實現的,因此這個類對外提供了兩個接口:OnGestureListener,OnDoubleTapListener,還有一個內部類SimpleOnGestureListener,SimpleOnGestureListener類是GestureDetector提供給我們的一個更方便的響應不同手勢的類,這個類實現了上述兩個接口(但是所有的方法體都是空的),該類是static class,也就是說它實際上是一個外部類。程序員可以在外部繼承這個類,重寫裏麵的手勢處理方法。
通過GestureDetector的構造方法可以將SimpleOnGestureListener對象傳遞進去,這樣GestureDetector能處理不同的手勢了。
2. 具體用法:
2.1
private class DefaultGestureListener extends SimpleOnGestureListener{ @Override public boolean onSingleTapUp(MotionEvent e) { return false; } @Override public void onLongPress(MotionEvent e) { } /** * @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 e1 and 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 e1 and e2. 無論是用手拖動view,或者是以拋的動作滾動,都會多次觸發 ,這個方法在ACTION_MOVE動作發生時就會觸發 參看GestureDetector的onTouchEvent方法源碼 * */ @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } /** * @param e1 第1個ACTION_DOWN MotionEvent 並且隻有一個 * @param e2 最後一個ACTION_MOVE MotionEvent * @param velocityX X軸上的移動速度,像素/秒 * @param velocityY Y軸上的移動速度,像素/秒 * 這個方法發生在ACTION_UP時才會觸發 參看GestureDetector的onTouchEvent方法源碼 * * */ @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onDown(MotionEvent e) { return false; } @Override public boolean onDoubleTap(MotionEvent e) { return false; } @Override public boolean onDoubleTapEvent(MotionEvent e) { return false; } /** * 這個方法不同於onSingleTapUp,他是在GestureDetector確信用戶在第一次觸摸屏幕後,沒有緊跟著第二次觸摸屏幕,也就是不是“雙擊”的時候觸發 * */ @Override public boolean onSingleTapConfirmed(MotionEvent e) { return false; } }
2.2
public GestureDetector (Context context, GestureDetector.OnGestureListener listener) //通過構造方法將手勢響應交給手勢識別類
2.3
在OnTouchListener的onTouch方法中
private OnTouchListener gestureTouchListener = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return gDetector.onTouchEvent(event); } };
ok,到此為止就結束了.
3.案例:
package com.android; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.widget.Button; public class Res extends Activity implements View.OnTouchListener { Button btn = null; private GestureDetector mGestureDetector = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); btn = (Button) findViewById(R.id.button); btn.setOnTouchListener(this); mGestureDetector = new GestureDetector(this, new LearnGestureListener()); } public boolean onTouch(View view, MotionEvent event) { return mGestureDetector.onTouchEvent(event); } class LearnGestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onSingleTapUp(MotionEvent ev) { Log.d("DEBUG","onSingleTapUp"); return true; } @Override public void onShowPress(MotionEvent ev) { Log.d("DEBUG","onShowPress"); } @Override public void onLongPress(MotionEvent ev) { Log.d("DEBUG","onLongPress"); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { Log.d("DEBUG","onScroll"); return true; } @Override public boolean onDown(MotionEvent ev) { Log.d("DEBUG","onDownd"); return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { Log.d("DEBUG","onFling"); return true; } public boolean onDoubleTap(MotionEvent event){ Log.d("DEBUG","onDoubleTap"); return true; } } }
4.遇到的問題:
1. onFling(***)無法觸發
通過設置 mListView.setLongClickable(true);即可(我處理的是ListView的手勢事件),隻有這樣,view才能夠處理不同於Tap(輕觸)的hold(即ACTION_MOVE,或者多個ACTION_DOWN),我們同樣可以通過layout定義中的android:longClickable來做到這一點。
2. 用戶長按手機屏幕,就會觸發長按事件,離開屏幕時,就會觸發up事件,但是SimpleOnGestureListener沒有對longPress事件的up事件對外提供接口
解決辦法:
類似於這樣,截獲up事件,因為所有的都是有OnTouchListener 先獲得,然後傳遞給SimpleOnGestureListener的,這裏有一點必須要注意:
截獲到up事件,我們進行了處理後,必須要將這個事件再交給SimpleOnGestureListener處理,雖然我們隻截獲長按事件的up,但是SimpleOnGestureListener對於長按事件的up也做了一些處理,隻是沒有對外提供接口。
做了什麼處理:
if (mInLongPress) { mHandler.removeMessages(TAP); mInLongPress = false; }
如果不交給SimpleOnGestureListener處理,那麼單擊動作也會觸發onLongPress方法。
private OnTouchListener gestureTouchListener = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: return gDetector.onTouchEvent(event); case MotionEvent.ACTION_UP: MyGesture.FlagInfo info = mGesture.getFlagInfo(); if(info.isConnected==true){ int firstVisiblePosition = mListView.getFirstVisiblePosition(); View view = mListView.getChildAt(info.position-firstVisiblePosition); if(view!=null){ view.setBackgroundResource(R.drawable.listitem_background_blue); info.isConnected = false; } } return gDetector.onTouchEvent(event); case MotionEvent.ACTION_MOVE: return gDetector.onTouchEvent(event); } return false; } };
總結:
1. 點擊屏幕上的某項的執行流程 有兩種情況,一種是時間很短,一種時間稍長
時間很短:onDown——–》onSingleTapUp——–》onSingleTapConfirmed
時間稍長:onDown——–》onShowPress——》onSingleTapUp——–》onSingleTapConfirmed
2. 長按事件
onDown——–》onShowPress——》onLongPress
3.拋:手指觸動屏幕後,稍微滑動後立即鬆開
onDown—–》onScroll—-》onScroll—-》onScroll—-》………—–>onFling
4.拖動
onDown——》onScroll—-》onScroll——》onFiling
注意:有的時候會觸發onFiling,但是有的時候不會觸發,個人理解是人的動作不標準所致。
最後更新:2017-04-02 06:52:05