Android 手势相关(一)

Android 手势相关(一)

本篇文章主要记录下android 手势相关的一些内容.

Android 提供了一套强大的手势识别框架,可以用来检测和处理用户的手势操作.

1: 手势识别

Android 提供了GestureDetector类来识别手势,通过GestureDetector可以检测用户的滑动,长按,双击等手势操作.

2: 手势监听器

android 中处理手势操作,需要我们实现GestureDetector.OnGestureListener接口,或者继承GestureDetector.SimpleOnGestureListener.

这里我们分开来讲述下这两种方式.

3: OnGestureListener接口

我们先实现下接口,添加打印日志:

java 复制代码
public class MyGesture implements GestureDetector.OnGestureListener {
    private static final String TAG = "MyGesture";

    @Override
    public boolean onDown(MotionEvent e) {
        Log.i(TAG, "onDown: "+e);
        return false;
    }

    @Override
    public void onShowPress(MotionEvent e) {
        Log.i(TAG, "onShowPress: "+e);
    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        Log.i(TAG, "onSingleTapUp: "+e);
        return false;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        Log.i(TAG, "onScroll: " +e1+" "+e2);
        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {
        Log.i(TAG, "onLongPress: "+e);
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        Log.i(TAG, "onFling: "+e1 +" "+e2);
        return false;
    }
}
  1. onDown(): 手势按下 MotionEvent.ACTION_DOWN
  2. onShowPress(): 用户已经按下,但是还没有执行移动/向上的移动操作.(这里我们可以给出高亮显示,增强显示效果) MotionEvent.ACTION_DOWN
  3. onSingleTapUp(): 用户手势抬起时的动作. MotionEvent.ACTION_UP
  4. onScroll(): 屏幕滑动 包括两个MotionEvent.ACTION_DOWN,MotionEvent.ACTION_MOVE
  5. onLongPress(): 长按 ACTION_DOWN
  6. onFling():迅速滑动

测试:

1: 手势按下->抬起

onDown->onSingleTapUp

java 复制代码
2024-03-27 11:22:18.236 6675-6675/? I/MyGesture: onDown: 
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=359.5007, y[0]=444.70743, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=175867619, downTime=175867619, deviceId=2, source=0x1002, displayId=0 }

2024-03-27 11:22:18.294 6675-6675/? I/MyGesture: onSingleTapUp: 
    MotionEvent { action=ACTION_UP, actionButton=0, id[0]=0, x[0]=359.5007, y[0]=444.70743, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=175867683, downTime=175867619, deviceId=2, source=0x1002, displayId=0 }
2: 长按不抬起

onDown->onShowPress->onLongPress

java 复制代码
2024-03-27 11:24:31.611 6675-6675/? I/MyGesture: onDown: 
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=550.2358, y[0]=541.6437, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=176000997, downTime=176000997, deviceId=2, source=0x1002, displayId=0 }

2024-03-27 11:24:31.706 6675-6675/? I/MyGesture: onShowPress: 
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=550.2358, y[0]=541.6437, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=176000997, downTime=176000997, deviceId=2, source=0x1002, displayId=0 }

2024-03-27 11:24:32.008 6675-6675/? I/MyGesture: onLongPress: 
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=550.2358, y[0]=541.6437, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=176000997, downTime=176000997, deviceId=2, source=0x1002, displayId=0 }
3: 屏幕上来回滑动

onDown->onShowPress->onScroll->onScroll

java 复制代码
2024-03-27 11:26:18.190 6675-6675/? I/MyGesture: onDown: 
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=146.79613, y[0]=707.53455, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=176107576, downTime=176107576, deviceId=2, source=0x1002, displayId=0 }

2024-03-27 11:26:18.285 6675-6675/? I/MyGesture: onShowPress: 
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=146.79613, y[0]=707.53455, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=176107576, downTime=176107576, deviceId=2, source=0x1002, displayId=0 }

2024-03-27 11:26:18.345 6675-6675/? I/MyGesture: onScroll: 
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=146.79613, y[0]=707.53455, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=176107576, downTime=176107576, deviceId=2, source=0x1002, displayId=0 } 
    MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=195.22885, y[0]=706.0355, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=2, eventTime=176107730, downTime=176107576, deviceId=2, source=0x1002, displayId=0 }


2024-03-27 11:26:18.361 6675-6675/? I/MyGesture: onScroll: 
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=146.79613, y[0]=707.53455, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=176107576, downTime=176107576, deviceId=2, source=0x1002, displayId=0 } 
    MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=245.15952, y[0]=705.03613, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=2, eventTime=176107747, downTime=176107576, deviceId=2, source=0x1002, displayId=0 }
4: 快速划过

onDown->onScroll->onScroll->onFling

java 复制代码
2024-03-27 11:28:58.135 6675-6675/? I/MyGesture: onDown: 
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=185.74203, y[0]=596.6075, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=176267521, downTime=176267521, deviceId=2, source=0x1002, displayId=0 }
2024-03-27 11:28:58.170 6675-6675/? I/MyGesture: onScroll: 
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=185.74203, y[0]=596.6075, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=176267521, downTime=176267521, deviceId=2, source=0x1002, displayId=0 } 
    MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=361.2865, y[0]=554.5809, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=3, eventTime=176267556, downTime=176267521, deviceId=2, source=0x1002, displayId=0 }
2024-03-27 11:28:58.187 6675-6675/? I/MyGesture: onScroll: 
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=185.74203, y[0]=596.6075, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=176267521, downTime=176267521, deviceId=2, source=0x1002, displayId=0 } 
    MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=519.8522, y[0]=535.2958, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=2, eventTime=176267573, downTime=176267521, deviceId=2, source=0x1002, displayId=0 }
2024-03-27 11:28:58.204 6675-6675/? I/MyGesture: onScroll: 
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=185.74203, y[0]=596.6075, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=176267521, downTime=176267521, deviceId=2, source=0x1002, displayId=0 } 
    MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=681.7713, y[0]=530.18, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=2, eventTime=176267589, downTime=176267521, deviceId=2, source=0x1002, displayId=0 }
2024-03-27 11:28:58.210 6675-6675/? I/MyGesture: onScroll: 
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=185.74203, y[0]=596.6075, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=176267521, downTime=176267521, deviceId=2, source=0x1002, displayId=0 } 
    MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=718.0028, y[0]=530.6509, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=176267593, downTime=176267521, deviceId=2, source=0x1002, displayId=0 }
2024-03-27 11:28:58.210 6675-6675/? I/MyGesture: onFling: 
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=185.74203, y[0]=596.6075, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=176267521, downTime=176267521, deviceId=2, source=0x1002, displayId=0 } 
    MotionEvent { action=ACTION_UP, actionButton=0, id[0]=0, x[0]=718.0028, y[0]=530.6509, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=176267600, downTime=176267521, deviceId=2, source=0x1002, displayId=0 }

4: SimpleOnGestureListener类

继承SimpleOnGestureListener,代码如下:

java 复制代码
public class MyGesture2 extends GestureDetector.SimpleOnGestureListener {
    private static final String TAG = "MyGesture2";
    @Override
    public boolean onDown(MotionEvent e) {
        Log.i(TAG, "onDown:\n"+e);
        return super.onDown(e);
    }

    @Override
    public void onShowPress(MotionEvent e) {
        Log.i(TAG, "onShowPress:\n"+e);
        super.onShowPress(e);
    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        Log.i(TAG, "onSingleTapUp:\n"+e);
        return super.onSingleTapUp(e);
    }

    @Override
    public void onLongPress(MotionEvent e) {
        Log.i(TAG, "onLongPress:\n"+e);
        super.onLongPress(e);
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        Log.i(TAG, "onScroll:\n"+e1+"\n"+e2+"\n");
        return super.onScroll(e1, e2, distanceX, distanceY);
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        Log.i(TAG, "onFling:\n"+e1+"\n"+e2+"\n");
        return super.onFling(e1, e2, velocityX, velocityY);
    }

    @Override
    public boolean onDoubleTap(MotionEvent e) {
        Log.i(TAG, "onDoubleTap:\n"+e);
        return super.onDoubleTap(e);
    }

    @Override
    public boolean onDoubleTapEvent(MotionEvent e) {
        Log.i(TAG, "onDoubleTapEvent:\n"+e);
        return super.onDoubleTapEvent(e);
    }

    @Override
    public boolean onContextClick(MotionEvent e) {
        Log.i(TAG, "onContextClick:\n"+e);
        return super.onContextClick(e);
    }

    @Override
    public boolean onSingleTapConfirmed(MotionEvent e) {
        Log.i(TAG, "onSingleTapConfirmed:\n"+e);
        return super.onSingleTapConfirmed(e);
    }

}

SimpleOnGestureListener类实际上继承了OnGestureListener, OnDoubleTapListener, OnContextClickListener这三个接口.

这里我们只需要关注OnDoubleTapListener以及OnContextClickListener即可.

  1. onSingleTapConfirmed():用户在屏幕上进行了单击操作
  2. onDoubleTap(): 发生双击时 , 参数MotionEvent代表的是第一次向下点击的事件
  3. onDoubleTapEvent():双击手势发生时发出的通知, MotionEvent可以是向下,移动,向上.
  4. onContextClick():

测试:

1.手势按下->抬起

onDown->onSingleTapUp->onSingleTapConfirmed

java 复制代码
2024-03-27 11:53:46.537 9897-9897/? I/MyGesture2: onDown:
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=380.4716, y[0]=401.73572, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=177755922, downTime=177755922, deviceId=2, source=0x1002, displayId=0 }
2024-03-27 11:53:46.596 9897-9897/? I/MyGesture2: onSingleTapUp:
    MotionEvent { action=ACTION_UP, actionButton=0, id[0]=0, x[0]=380.4716, y[0]=401.73572, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=177755985, downTime=177755922, deviceId=2, source=0x1002, displayId=0 }
2024-03-27 11:53:46.837 9897-9897/? I/MyGesture2: onSingleTapConfirmed:
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=380.4716, y[0]=401.73572, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=177755922, downTime=177755922, deviceId=2, source=0x1002, displayId=0 }
2: 双击

onDown->onSingleTapUp->onDoubleTap(ACTION_DOWN)->onDoubleTapEvent(ACTION_DOWN)

->onDown->onDoubleTapEvent(ACTION_MOVE)->onDoubleTapEvent(ACTION_MOVE)->onDoubleTapEvent(ACTION_UP)

java 复制代码
2024-03-24 11:48:03.028 9897-9897/? I/MyGesture2: onDown:
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=387.46185, y[0]=547.6397, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=177412412, downTime=177412412, deviceId=2, source=0x1002, displayId=0 }
2024-03-24 11:48:03.071 9897-9897/? I/MyGesture2: onSingleTapUp:
    MotionEvent { action=ACTION_UP, actionButton=0, id[0]=0, x[0]=387.46185, y[0]=547.6397, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=177412459, downTime=177412412, deviceId=2, source=0x1002, displayId=0 }
2024-03-24 11:48:03.311 9897-9897/? I/MyGesture2: onDoubleTap:
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=387.46185, y[0]=547.6397, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=177412412, downTime=177412412, deviceId=2, source=0x1002, displayId=0 }
2024-03-24 11:48:03.312 9897-9897/? I/MyGesture2: onDoubleTapEvent:
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=384.46603, y[0]=527.6529, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=177412698, downTime=177412698, deviceId=2, source=0x1002, displayId=0 }
2024-03-24 11:48:03.313 9897-9897/? I/MyGesture2: onDown:
    MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=384.46603, y[0]=527.6529, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=177412698, downTime=177412698, deviceId=2, source=0x1002, displayId=0 }
2024-03-24 11:48:03.332 9897-9897/? I/MyGesture2: onDoubleTapEvent:
    MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=384.46603, y[0]=527.6529, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=2, eventTime=177412715, downTime=177412698, deviceId=2, source=0x1002, displayId=0 }
2024-03-24 11:48:03.348 9897-9897/? I/MyGesture2: onDoubleTapEvent:
    MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=384.46603, y[0]=527.6529, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=2, eventTime=177412733, downTime=177412698, deviceId=2, source=0x1002, displayId=0 }
2024-03-24 11:48:03.355 9897-9897/? I/MyGesture2: onDoubleTapEvent:
    MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=384.46603, y[0]=527.6529, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=177412738, downTime=177412698, deviceId=2, source=0x1002, displayId=0 }
2024-03-24 11:48:03.356 9897-9897/? I/MyGesture2: onDoubleTapEvent:
    MotionEvent { action=ACTION_UP, actionButton=0, id[0]=0, x[0]=384.46603, y[0]=527.6529, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=177412744, downTime=177412698, deviceId=2, source=0x1002, displayId=0 }
相关推荐
喜欢打篮球的普通人2 小时前
LLVM Backend Lowering 从入门到实战:把 IR 变成机器码的完整链路
android·java·数据库
萝卜er5 小时前
BroadcastReceiver 静态注册与动态注册-《Android深水区(七)》
android
萝卜er6 小时前
ContentProvider 与跨进程数据访问-《Android深水区(八)》
android
萝卜er6 小时前
Service、前台服务与后台限制-《Android深水区(六)》
android
萝卜er6 小时前
Android 存储体系与分区存储-《Android深水区(十二)》
android
会编程的吕洞宾6 小时前
DeepAgents In Action学习(Second)
android·java·学习
太子釢7 小时前
用 AI 完整实现 Github 客户端:基于 KMP + SwiftUI + Compose
android·人工智能·ios
汪海游龙7 小时前
本地源码还是 Maven 版本?Gradle composite build 双轨依赖的正确接法
android·ci/cd·kotlin
k3x1n7 小时前
三星安卓系统BUG排查记录:云闪付、铁路12306、个人所得税、中国移动等App,长期闪退的根本原因分析
android·逆向
网安蟹佬霸8 小时前
CTF Web方向解题全攻略:从信息收集到getshell(附实战payload与脚本)
android·前端·网络·安全·web安全·网络安全·网安