當使用者將單指或多根手指放在 觸控螢幕和您的應用程式,會將這種觸控模式解讀為手勢。有 手勢偵測分成兩個階段:
- 收集觸控事件資料。
- 解讀資料以判斷資料是否符合 以及應用程式支援的手勢
AndroidX 類別
本文件中的範例使用
GestureDetectorCompat
和
MotionEventCompat
類別這些類別位於 AndroidX
程式庫。請盡可能使用 AndroidX 類別,以提供相容性
舊款裝置
MotionEventCompat
不會取代
MotionEvent
類別而是提供靜態的公用程式方法,
MotionEvent
物件,用於接收與該動作相關的動作
活動。
收集資料
當使用者將單指或多指放在螢幕上時,會觸發
回呼
onTouchEvent()
請參閱接收觸控事件的檢視區塊。針對各個觸控順序
例如位置、壓力、大小等事件
手指- 算法為手勢,onTouchEvent()
表示
觸發多次。
這個手勢會在使用者首次輕觸螢幕時開始,繼續做為
系統會追蹤使用者的手指或手指位置
這會擷取使用者最後一個手指離開畫面的最終事件。
在此互動中,MotionEvent
已傳送至
onTouchEvent()
會提供每次互動的詳細資料。您的應用程式
可以使用 MotionEvent
提供的資料,判斷
或手勢操控手勢
擷取活動或檢視畫面的觸控事件
攔截 Activity
中的觸控事件或
View
,覆寫 onTouchEvent()
回呼。
下列程式碼片段使用
getAction()
,從 event
參數擷取使用者執行的動作。
如此一來,您就能根據所需的原始資料,判斷自己重視的手勢
Kotlin
class MainActivity : Activity() { ... // This example shows an Activity. You can use the same approach if you are // subclassing a View. override fun onTouchEvent(event: MotionEvent): Boolean { return when (event.action) { MotionEvent.ACTION_DOWN -> { Log.d(DEBUG_TAG, "Action was DOWN") true } MotionEvent.ACTION_MOVE -> { Log.d(DEBUG_TAG, "Action was MOVE") true } MotionEvent.ACTION_UP -> { Log.d(DEBUG_TAG, "Action was UP") true } MotionEvent.ACTION_CANCEL -> { Log.d(DEBUG_TAG, "Action was CANCEL") true } MotionEvent.ACTION_OUTSIDE -> { Log.d(DEBUG_TAG, "Movement occurred outside bounds of current screen element") true } else -> super.onTouchEvent(event) } } }
Java
public class MainActivity extends Activity { ... // This example shows an Activity. You can use the same approach if you are // subclassing a View. @Override public boolean onTouchEvent(MotionEvent event){ switch(event.getAction()) { case (MotionEvent.ACTION_DOWN) : Log.d(DEBUG_TAG,"Action was DOWN"); return true; case (MotionEvent.ACTION_MOVE) : Log.d(DEBUG_TAG,"Action was MOVE"); return true; case (MotionEvent.ACTION_UP) : Log.d(DEBUG_TAG,"Action was UP"); return true; case (MotionEvent.ACTION_CANCEL) : Log.d(DEBUG_TAG,"Action was CANCEL"); return true; case (MotionEvent.ACTION_OUTSIDE) : Log.d(DEBUG_TAG,"Movement occurred outside bounds of current screen element"); return true; default : return super.onTouchEvent(event); } }
這個程式碼會在使用者輕觸時,於 Logcat 產生如下訊息, 觸控與保留及拖曳:
GESTURES D Action was DOWN GESTURES D Action was UP GESTURES D Action was MOVE
針對自訂手勢,你可以自行處理這些事件,
判斷這些手勢是否代表您需要處理的手勢。不過,
應用程式使用常用手勢,例如輕觸兩下、觸控和保管、快速滑過等
也可以利用
GestureDetector
類別GestureDetector
可讓你更容易偵測
而無需自行處理個別觸控事件這是
進一步討論,請參閱「偵測手勢」一節。
擷取單一檢視畫面的觸控事件
除了 onTouchEvent()
以外,您也可以附加
View.OnTouchListener
物件附加至任何 View
物件
setOnTouchListener()
方法。如此一來,您不必將
現有的 View
,如以下範例所示:
Kotlin
findViewById<View>(R.id.my_view).setOnTouchListener { v, event -> // Respond to touch events. true }
Java
View myView = findViewById(R.id.my_view); myView.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Respond to touch events. return true; } });
建立會傳回 false
的事件監聽器
ACTION_DOWN
事件。
如此一來,後續發生時就不會呼叫監聽器
「ACTION_MOVE
」和
ACTION_UP
序列
事件。這是因為所有玩家的起點都是 ACTION_DOWN
觸控事件。
如要建立自訂檢視畫面,
onTouchEvent()
(如前所述)。
偵測手勢
Android 提供 GestureDetector
類別來偵測常見的
手勢。這項功能支援的部分手勢包括
onDown()
,
onLongPress()
,
和
onFling()
。
您可以將 GestureDetector
與
onTouchEvent()
方法。
偵測所有支援的手勢
將 GestureDetectorCompat
物件執行個體化時,
需要採用可實作
GestureDetector.OnGestureListener
存取 APIGestureDetector.OnGestureListener
會在
就會發生特定觸控事件為了實現您的
GestureDetector
物件用於接收事件,覆寫檢視畫面或
活動的 onTouchEvent()
方法,並傳遞所有觀察到的事件
傳送至偵測工具執行個體
在以下程式碼片段中,從true
個別 on<TouchEvent>
方法會指出
處理觸控事件。false
的傳回值會將事件向下傳遞
經由檢視堆疊,直到觸控成功處理為止。
如果您在測試應用程式中執行以下程式碼片段,可以大致瞭解
當使用者與觸控螢幕互動時
MotionEvent
的內容是針對每個觸控事件提供。然後
計算簡易互動會產生多少資料。
Kotlin
private const val DEBUG_TAG = "Gestures" class MainActivity : Activity(), GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener { private lateinit var mDetector: GestureDetectorCompat // Called when the activity is first created. public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Instantiate the gesture detector with the // application context and an implementation of // GestureDetector.OnGestureListener. mDetector = GestureDetectorCompat(this, this) // Set the gesture detector as the double-tap // listener. mDetector.setOnDoubleTapListener(this) } override fun onTouchEvent(event: MotionEvent): Boolean { return if (mDetector.onTouchEvent(event)) { true } else { super.onTouchEvent(event) } } override fun onDown(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDown: $event") return true } override fun onFling( event1: MotionEvent, event2: MotionEvent, velocityX: Float, velocityY: Float ): Boolean { Log.d(DEBUG_TAG, "onFling: $event1 $event2") return true } override fun onLongPress(event: MotionEvent) { Log.d(DEBUG_TAG, "onLongPress: $event") } override fun onScroll( event1: MotionEvent, event2: MotionEvent, distanceX: Float, distanceY: Float ): Boolean { Log.d(DEBUG_TAG, "onScroll: $event1 $event2") return true } override fun onShowPress(event: MotionEvent) { Log.d(DEBUG_TAG, "onShowPress: $event") } override fun onSingleTapUp(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onSingleTapUp: $event") return true } override fun onDoubleTap(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDoubleTap: $event") return true } override fun onDoubleTapEvent(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDoubleTapEvent: $event") return true } override fun onSingleTapConfirmed(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onSingleTapConfirmed: $event") return true } }
Java
public class MainActivity extends Activity implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener{ private static final String DEBUG_TAG = "Gestures"; private GestureDetectorCompat mDetector; // Called when the activity is first created. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Instantiate the gesture detector with the // application context and an implementation of // GestureDetector.OnGestureListener. mDetector = new GestureDetectorCompat(this,this); // Set the gesture detector as the double-tap // listener. mDetector.setOnDoubleTapListener(this); } @Override public boolean onTouchEvent(MotionEvent event){ if (this.mDetector.onTouchEvent(event)) { return true; } return super.onTouchEvent(event); } @Override public boolean onDown(MotionEvent event) { Log.d(DEBUG_TAG,"onDown: " + event.toString()); return true; } @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString()); return true; } @Override public void onLongPress(MotionEvent event) { Log.d(DEBUG_TAG, "onLongPress: " + event.toString()); } @Override public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX, float distanceY) { Log.d(DEBUG_TAG, "onScroll: " + event1.toString() + event2.toString()); return true; } @Override public void onShowPress(MotionEvent event) { Log.d(DEBUG_TAG, "onShowPress: " + event.toString()); } @Override public boolean onSingleTapUp(MotionEvent event) { Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString()); return true; } @Override public boolean onDoubleTap(MotionEvent event) { Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString()); return true; } @Override public boolean onDoubleTapEvent(MotionEvent event) { Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString()); return true; } @Override public boolean onSingleTapConfirmed(MotionEvent event) { Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString()); return true; } }
偵測支援手勢的子集
如果只想處理一些手勢,
GestureDetector.SimpleOnGestureListener
而不是實作 GestureDetector.OnGestureListener
存取 API
GestureDetector.SimpleOnGestureListener
提供
所有應用程式的
傳回 on<TouchEvent>
方法
false
。這可以只覆寫您
大家在乎的事舉例來說,下列程式碼片段會建立
GestureDetector.SimpleOnGestureListener
和覆寫設定
onFling()
和onDown()
。
無論您使用 GestureDetector.OnGestureListener
還是
GestureDetector.SimpleOnGestureListener
,最佳做法是
實作會傳回 true
的 onDown()
方法。這個
這是因為所有手勢的開頭都是 onDown()
訊息。如果發生以下情況:
從 onDown()
傳回 false
,如
根據預設,GestureDetector.SimpleOnGestureListener
會
假設您要忽略手勢的其餘部分
GestureDetector.OnGestureListener
並未呼叫。這可能
應用程式異常狀況僅從以下日期傳回 false
:
如果你真正想忽略整個手勢,則請onDown()
。
Kotlin
private const val DEBUG_TAG = "Gestures" class MainActivity : Activity() { private lateinit var mDetector: GestureDetectorCompat public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mDetector = GestureDetectorCompat(this, MyGestureListener()) } override fun onTouchEvent(event: MotionEvent): Boolean { mDetector.onTouchEvent(event) return super.onTouchEvent(event) } private class MyGestureListener : GestureDetector.SimpleOnGestureListener() { override fun onDown(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDown: $event") return true } override fun onFling( event1: MotionEvent, event2: MotionEvent, velocityX: Float, velocityY: Float ): Boolean { Log.d(DEBUG_TAG, "onFling: $event1 $event2") return true } } }
Java
public class MainActivity extends Activity { private GestureDetectorCompat mDetector; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mDetector = new GestureDetectorCompat(this, new MyGestureListener()); } @Override public boolean onTouchEvent(MotionEvent event){ if (this.mDetector.onTouchEvent(event)) { return true; } return super.onTouchEvent(event); } class MyGestureListener extends GestureDetector.SimpleOnGestureListener { private static final String DEBUG_TAG = "Gestures"; @Override public boolean onDown(MotionEvent event) { Log.d(DEBUG_TAG,"onDown: " + event.toString()); return true; } @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString()); return true; } } }