当用户将一根或多根手指放在屏幕上时,即发生了触摸手势 触摸屏,并且您的应用会将这种轻触模式解读为手势。那里 手势检测的两个阶段:
- 正在收集触摸事件数据。
- 解读数据以确定它是否符合 手势。
AndroidX 类
本文档中的示例使用
GestureDetectorCompat
和
MotionEventCompat
类。这些类位于 AndroidX 中
媒体库。尽可能使用 AndroidX 类来提供与
早期版本的设备。
MotionEventCompat
不能替代
MotionEvent
类。相反,它可以提供静态实用程序方法,
MotionEvent
对象,以接收与其关联的操作
事件。
收集数据
当用户将一个或多个手指放在屏幕上时,这会触发
回拨
onTouchEvent()
对接收触摸事件的视图进行定制。对于每个轻触序列
例如位置、压力、大小和添加另一个
手指 - 识别为手势,onTouchEvent()
为
多次触发
手势在用户首次轻触屏幕时开始,并作为
系统会跟踪用户手指的位置,
捕获用户最后一根手指离开屏幕的最终事件。
在整个互动过程中,MotionEvent
onTouchEvent()
会提供每次互动的详细信息。您的应用
可以根据 MotionEvent
提供的数据来确定
它关心的手势。
捕获 Activity 或视图的轻触事件
如需拦截 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
界面。GestureDetector.OnGestureListener
会在发生以下情况时通知用户:
会发生特定触摸事件。为了让您的
GestureDetector
对象来接收事件、替换视图或
activity 的 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
界面。
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; } } }