GestureDetector 和 ScrollView混用后onFling无法正常工作

ScrollView与GestureDetector触控冲突解决方案
本文介绍了解决ScrollView与GestureDetector触控事件冲突的问题。通过覆盖dispatchTouchEvent方法并手动分发MotionEvent给两者,确保了触控事件能够同时被处理。文章还提供了触发顺序的说明,并附带相关链接。

开始在学习用GestureDetector中的onFling,都正常,可是加入ScrollView后就没法响应了, google了很久,似乎也没个具体的方法,后来看到说用dispatchTouchEvent(MotionEvent ev) 的方法,果然可以,不过帖子没说具体怎么办,查了些文档,试验了几个方法,果然找到了一个,和大家分享下。
具体原因我也不是很明白,可能是因为ScrollView抢占了MotionEvent 事件,所以GestureDetector
捕获不到任何的touch event,自然就不会相应了,方法是@override
public boolean dispatchTouchEvent(MotionEvent ev) {
mGestureDetector.onTouchEvent(ev);
scroll.onTouchEvent(ev);
return super.dispatchTouchEvent(ev);

}
然后发送MotionEvent分别给你的GestureDetector和ScrollView,而不是dispatchMotionEvent,我猜 测dispatch后会被ScrollView先取走,从而GestureDetector就无法响应了,所以这里就都派发出去。
声明,我试验过了,是可以的,不过没有理论上面的支撑,所以哪位知道的还请给个具体些的解释哈

eg1:

从今天解决的一个问题了解到, viewGroup的dispatchTouchEvent方法会在其onInterceptTouchEvent方法之前被触发.

又搜了些资料,个人觉得最受用的总结如下:

首先触发ACTIVITY的dispatchTouchEvent

然后触发ACTIVITY的onUserInteraction

然后触发LAYOUT的dispatchTouchEvent

然后触发LAYOUT的onInterceptTouchEvent

供参考的文章蛮多的,我不再废话了:

http://blog.youkuaiyun.com/iefreer/archive/2009/09/23/4586351.aspx

http://blog.youkuaiyun.com/ddna/archive/2010/04/11/5473293.aspx

http://blog.youkuaiyun.com/ddna/archive/2010/04/05/5451722.aspx

http://blog.youkuaiyun.com/G_rrrr/archive/2009/11/24/4861189.aspx

摘自eoeandroid

`GestureDetector` `MotionEvent` **不是一样的**,它们在 Android 触摸事件处理体系中扮演不同的角色: --- ## ✅ 简明结论 | 对比项 | `MotionEvent` | `GestureDetector` | |--------|----------------|--------------------| | 类型 | 原始输入事件类 | 手势识别工具类 | | 作用 | 表示一次触摸的原始数据(如按下、移动、抬起) | 分析一连串 `MotionEvent`,识别出“手势”含义(如滑动、长按、双击) | | 关系 | 是 `GestureDetector` 的输入 | 使用 `MotionEvent` 来判断用户做了什么手势 | > 🔹 可以理解为: > - `MotionEvent` 是“原始信号”(比如:手指在 (100,200) 按下,然后滑到 (300,400)) > - `GestureDetector` 是“翻译器”,把这一系列动作翻译成:“你刚刚向右滑动了!” --- ## 🧱 详细解释 ### 1. `MotionEvent`:触摸事件的“原子单位” 每次用户与屏幕交互时,系统都会生成一个或多个 `MotionEvent` 对象。 #### 常见类型: ```java MotionEvent.ACTION_DOWN // 手指按下 MotionEvent.ACTION_MOVE // 手指移动 MotionEvent.ACTION_UP // 手指抬起 MotionEvent.ACTION_CANCEL // 事件被中断 ``` #### 示例代码:直接处理 MotionEvent ```java @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: Log.d("Touch", "按下: (" + x + ", " + y + ")"); break; case MotionEvent.ACTION_MOVE: Log.d("Touch", "移动中"); break; case MotionEvent.ACTION_UP: Log.d("Touch", "抬起"); break; } return true; } ``` 📌 这种方式你能知道每一个点发生了什么,但**无法直接判断这是“滑动”还是“点击”** —— 你需要自己写逻辑来判断。 --- ### 2. `GestureDetector`:帮你“看懂”手势 它是一个封装好的工具类,接收 `MotionEvent` 并回调高级语义事件。 #### 使用步骤: ##### Step 1: 创建 GestureDetector ```java private GestureDetector mGestureDetector; mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDown(MotionEvent e) { Log.d("Gesture", "按下"); return true; } @Override public boolean onSingleTapUp(MotionEvent e) { Log.d("Gesture", "单击"); return true; } @Override public void onLongPress(MotionEvent e) { Log.d("Gesture", "长按"); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { Log.d("Gesture", "快速滑动!"); return true; } }); ``` ##### Step 2: 在 onTouchEvent 中传递事件 ```java @Override public boolean onTouchEvent(MotionEvent event) { // 把原始事件交给 GestureDetector 处理 return mGestureDetector.onTouchEvent(event); } ``` ✅ 现在你不需要手动计算位移时间,就能知道用户是否“滑动”、“双击”或“长按”。 --- ## 🔍 对比举例:实现“左滑删除” | 方式 | 实现难度 | 是否推荐 | |------|----------|---------| | ❌ 仅用 `MotionEvent` | 需要记录 down/up 时间、坐标差、速度估算……复杂易错 | 不推荐 | | ✅ 使用 `GestureDetector` | 直接重写 `onFling()` 判断方向即可 | 推荐 | ```java @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float vx, float vy) { float deltaX = e2.getX() - e1.getX(); if (deltaX > 100 && Math.abs(vx) > 100) { Log.d("Swipe", "向右滑动"); } else if (deltaX < -100 && Math.abs(vx) > 100) { Log.d("Swipe", "向左滑动 → 删除!"); } return true; } ``` --- ## 💡 更进一步:嵌套使用关系图 ``` 屏幕触摸 ↓ [MotionEvent] ← 系统产生(ACTION_DOWN/MOVE/UP) ↓ GestureDetector.onTouchEvent(event) ↓ GestureDetector 内部分析这些事件序列 ↓ 触发对应的回调方法: • onSingleTapConfirmed() • onDoubleTap() • onLongPress() • onFling() • onScroll() ``` 👉 所以: > `GestureDetector` 是基于 `MotionEvent` 构建的更高层抽象,让你不必从零开始识别手势。 --- ## ⚠️ 注意事项 | 问题 | 解决方案 | |------|----------| | `GestureDetector` 不支持双指缩放 | 改用 `ScaleGestureDetector` | | 滑动点击冲突 | 使用 `onSingleTapConfirmed()` 而非 `onSingleTapUp()` | | 必须返回 `true` 才能持续接收事件 | 否则后续 MOVE/UP 不会到达 | | 在 `RecyclerView` 或 `ViewPager` 中可能被拦截 | 需配合 `requestDisallowInterceptTouchEvent()` | --- ## ✅ 总结 | 特性 | `MotionEvent` | `GestureDetector` | |------|---------------|------------------| | 层级 | 底层原始事件 | 高层语义识别 | | 用途 | 获取精确坐标时间 | 判断用户意图(滑动、点击等) | | 开发效率 | 低(需手动计算) | 高(封装良好) | | 是否替代关系 | ❌ 不是替代,而是基础 | ✅ 建立在 `MotionEvent` 之上 | > ✅ 最佳实践: > 在大多数 UI 组件中,优先使用 `GestureDetector` 来处理常见手势;只有在需要精细控制时才直接解析 `MotionEvent`。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值