尝试使用 Compose 方式

Jetpack Compose 是推荐用于 Android 的界面工具包。了解如何在 Compose 中使用触控和输入。

手势 →

“轻触手势”是指用户将一个或多个手指放在触摸屏上,并且您的应用会将这种轻触模式解读为手势。 手势检测分为两个阶段:

收集触摸事件数据。

解读数据以确定其是否符合您的应用支持的手势的条件。

AndroidX 类

本文档中的示例使用 GestureDetectorCompat 和 MotionEventCompat 类。这些类位于 AndroidX

Library 中。请尽可能使用 AndroidX 类,以便与旧版设备兼容。

MotionEventCompat 不是 not 类的替代项。MotionEvent而是提供静态实用程序方法,您可以向这些方法传递 MotionEvent 对象,以便接收与相应事件相关的操作。

收集数据

当用户在屏幕上放置一个或多个手指时,触发事件的视图上的

回调

onTouchEvent()

。对于最终被识别为手势的每个轻触事件序列(例如位置、按压、调整大小、添加另一个手指),onTouchEvent() 都会多次被触发。

手势在用户首次触摸屏幕时开始,在系统跟踪用户的手指位置时继续,并通过捕获用户最后一个手指离开屏幕的最终事件结束。

在此互动过程中,传递给 onTouchEvent() 的 MotionEvent 会提供每次互动的详细信息。您的应用可以使用 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() 之外,您还可以使用

setOnTouchListener()

方法将

View.OnTouchListener

对象附加到任何 View

对象。这样,您就可以监听轻触事件,而无需对现有 View 进行子类化,如以下示例所示:

Kotlin

findViewById(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;

}

});

请注意,不要创建针对 ACTION_DOWN 事件返回 false 的监听器。

如果您这样做,系统就不会为后续的 ACTION_MOVE 和 ACTION_UP 事件序列调用该监听器。这是因为 ACTION_DOWN 是所有轻触事件的起点。

如需创建自定义视图,可以按照上文所述替换 onTouchEvent()。

检测手势

Android 提供了用于检测常用手势的 GestureDetector 类。它支持的一些手势包括 onDown()、onLongPress() 和 onFling()。

您可以结合使用 GestureDetector 和上文所述的 onTouchEvent() 方法。

检测所有受支持的手势

实例化 GestureDetectorCompat 对象时,它采用的其中一个参数是实现 GestureDetector.OnGestureListener 接口的类。GestureDetector.OnGestureListener 会在发生特定触摸事件时通知用户。如需让 GestureDetector 对象能够接收事件,请替换视图或 activity 的 onTouchEvent() 方法,并将所有观察到的事件传递给检测器实例。

在以下代码段中,各个 on 方法返回 true 表示触摸事件已处理。如果返回值为 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 方法返回

false 来提供实现。这样,您就可以仅替换您关心的方法。例如,以下代码段会创建一个扩展 GestureDetector.SimpleOnGestureListener 并替换 onFling() 和 onDown() 的类。

无论您使用 GestureDetector.OnGestureListener 还是 GestureDetector.SimpleOnGestureListener,最佳做法都是实现返回 true 的 onDown() 方法。这是因为所有手势都以 onDown() 消息开头。如果您从 onDown() 返回 false(如 GestureDetector.SimpleOnGestureListener 默认执行的操作),系统会假定您要忽略手势的其余部分,并且不会调用 GestureDetector.OnGestureListener 的其他方法。这可能会导致应用中出现意外问题。只有在您确实想要忽略整个手势时,才从 onDown() 返回 false。

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;

}

}

}

其他资源

输入事件概览

传感器概览

将自定义视图设为互动式