检测常用手势

试用 Compose 方式
Jetpack Compose 是推荐在 Android 设备上使用的界面工具包。了解如何在 Compose 中使用触控和输入功能。
<ph type="x-smartling-placeholder"></ph> 手势 →

当用户将一根或多根手指放在屏幕上时,即发生了触摸手势 触摸屏,并且您的应用会将这种轻触模式解读为手势。那里 手势检测的两个阶段:

  1. 正在收集触摸事件数据。
  2. 解读数据以确定它是否符合 手势。

AndroidX 类

本文档中的示例使用 GestureDetectorCompatMotionEventCompat 类。这些类位于 AndroidX 中 媒体库。尽可能使用 AndroidX 类来提供与 早期版本的设备。 MotionEventCompat不能替代 MotionEvent 类。相反,它可以提供静态实用程序方法, MotionEvent 对象,以接收与其关联的操作 事件。

收集数据

当用户将一个或多个手指放在屏幕上时,这会触发 回拨 onTouchEvent() 对接收触摸事件的视图进行定制。对于每个轻触序列 例如位置、压力、大小和添加另一个 手指 - 识别为手势,onTouchEvent() 为 多次触发

手势在用户首次轻触屏幕时开始,并作为 系统会跟踪用户手指的位置, 捕获用户最后一根手指离开屏幕的最终事件。 在整个互动过程中,MotionEvent onTouchEvent() 会提供每次互动的详细信息。您的应用 可以根据 MotionEvent 提供的数据来确定 它关心的手势。

捕获 Activity 或视图的轻触事件

如需拦截 ActivityView,请替换 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_MOVEACTION_UP序列, 事件。这是因为 ACTION_DOWN 是所有 触摸事件。

如果您要创建自定义视图,则可以覆盖 onTouchEvent()(如前所述)。

检测手势

Android 提供了 GestureDetector 类,用于检测常见的 手势。它支持的手势包括 onDown(), onLongPress(), 和 onFling()。 您可以将 GestureDetectoronTouchEvent() 方法。

检测所有受支持的手势

当您实例化 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,最佳做法是 实现返回 trueonDown() 方法。本次 因为所有手势都以 onDown() 消息开头。如果您 从onDown()返回false,作为 GestureDetector.SimpleOnGestureListener 默认执行, 假设您想忽略其余的手势,以及 系统不会调用 GestureDetector.OnGestureListener。这可能会导致 出现意外问题仅从以下地点退回 falseonDown()(如果您确实想忽略整个手势)。

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;
        }
    }
}

其他资源