多点触控事件处理 ev.getAction() & MotionEvent.ACTION_MASK

本文介绍了一种在Android平台上实现多点触控的方法。通过重写Activity中的onTouchEvent并设置返回值为true,使系统能够接收多个触摸点。文章详细解析了MotionEvent的处理流程,并提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自 http://www.glmei.cn/?p=3084


把之前学过的东西都打包,方便以后调用。
    今天来个多点触控的,其实挺简单。
    网上教程大把。不过自己能体会才是自己的。写写自己的体会。
    第一个主要的点是Activity中的onTouchEvent(MotionEvent event);
    Override onTouchEvent(…)为以下形式:
    onTouchEvent(MotionEvent event){
          return super.onTouchEvent(event);
    }
    默认的情况下super.onTouchEvent(…)返回false,所以只有一个触摸点被传送。当把return的值改成true的时候,系统在得到true指令后,获得触摸点的监听器并没有被置失效,多点触控就得以实现了。当把值改为true之后,在方法内加个输出语句标记一下,可以看见event在多点触控的情况下,提取event内触碰点个数,会有有相应改变。不断得到屏幕事件的各种值,通过switch语句的筛选,就可以得到屏幕受到的触摸的情况。下面贴代码。其实跟GestureDetector常用方法差不多。
import android.view.MotionEvent;

public class CMultiTouchManager {

    private OnCMultiTouchListener cOnCMultiTouchListener = null;

    public CMultiTouchManager(){}
    public void setOnCMultiTouchListener(OnCMultiTouchListener listener){
        if (listener == null) {
            throw new IllegalStateException(“Listener could be null !”);
        }
        this.cOnCMultiTouchListener=listener;
    }
    public CMultiTouchManager(OnCMultiTouchListener listener) {
        if (listener == null) {
            throw new IllegalStateException(“Listener could be null !”);
        }
        this.cOnCMultiTouchListener = listener;
    }

    public void putTouchEvent(MotionEvent event) {
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            CMultiTouchManager.this.cOnCMultiTouchListener.onDown(
                    event.getPointerId(event.getPointerCount() – 1),
                    event.getX(), event.getY());
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            CMultiTouchManager.this.cOnCMultiTouchListener.onDown(
                    event.getPointerId(event.getPointerCount() – 1),
                    event.getX(), event.getY());
            break;
        case MotionEvent.ACTION_UP:
            CMultiTouchManager.this.cOnCMultiTouchListener.onUp(
                    event.getPointerId(event.getPointerCount() – 1),
                    event.getX(), event.getY());
            break;
        case MotionEvent.ACTION_POINTER_UP:
            CMultiTouchManager.this.cOnCMultiTouchListener.onUp(
                    event.getPointerId(event.getPointerCount() – 1),
                    event.getX(), event.getY());
            break;
        case MotionEvent.ACTION_MOVE:
            for (int i = 0; i < event.getPointerCount(); i++) {
                CMultiTouchManager.this.cOnCMultiTouchListener.onMove(
                        event.getPointerId(i), event.getX(i), event.getY(i));
            }
            break;
        }
        //在以上筛选代码中,down和up条件都是简单的只要确定在哪里按下跟抬起就可以。而每次move的条件都需要得到所有触摸点的坐标,才能及时调整,例如几个点同时滑动,需同时知道这几个点的滑动路径。

    }
}

interface OnCMultiTouchListener {
    public void onDown(int id, float x, float y);

    public void onUp(int id, float x, float y);

    public void onMove(int id, float x, float y);
}

    写好后,可以看到代码中有一个与运算(红字体部分)。目的是什么呢?
    先看看各动作的全局变量的内容:                               
  public static final int ACTION_MASK = 255=0000000011111111;
  public static final int ACTION_DOWN = 0=00000000;
  public static final int ACTION_UP = 00000001;
  public static final int ACTION_MOVE = 00000010;
  public static final int ACTION_CANCEL = 00000011;
  public static final int ACTION_OUTSIDE = 00000100;
  public static final int ACTION_POINTER_DOWN = 00000101;
  public static final int ACTION_POINTER_1_DOWN = 00000101;
  public static final int ACTION_POINTER_2_DOWN = 100000101;
  public static final int ACTION_POINTER_3_DOWN = 1000000101;
  public static final int ACTION_POINTER_UP = 00000110;
  public static final int ACTION_POINTER_1_UP = 00000110;
  public static final int ACTION_POINTER_2_UP = 100000110;
  public static final int ACTION_POINTER_3_UP = 1000000110;
  由以上可知,当ACTION_MASK&ACTION_POINTER_1/2/3_DOWN/UP=ACTION_MASK&ACTION_POINTER_DOWN/UP;
  从而可将不同的触摸归类为一个类。


`onInterceptTouchEvent(MotionEvent ev)` 是 Android 中 `ViewGroup` 的一个关键方法,用于判断是否需要拦截某个触摸事件并阻止它传递给子视图。我们来逐步分析您提供的代码片段: --- ### **代码功能解析** ```java public boolean onInterceptTouchEvent(MotionEvent ev) { // 判断当前触控来源是否为鼠标,并检查动作是否是按下操作 (ACTION_DOWN) if (ev.isFromSource(InputDevice.SOURCE_MOUSE) &amp;&amp; ev.getAction() == MotionEvent.ACTION_DOWN // 检查是否按下了鼠标的主键(通常是左键) &amp;&amp; ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY) // 调用自定义方法 isOnScrollbarThumb(x, y),检测触碰位置是否位于滚动条拇指区域 &amp;&amp; isOnScrollbarThumb(ev.getXDispatchLocation(0), ev.getYDispatchLocation(0)) ) { // 如果以上条件全部满足,则返回 true 表示拦截此事件 return true; } // 否则返回 false 表示不拦截该事件 return false; } ``` #### **逐行解释**: 1. **`isFromSource(InputDevice.SOURCE_MOUSE)`** - 确保输入设备的源是鼠标而不是其他设备(如手指、键盘等)。这限制了只有通过鼠标触发的操作才会进入后续逻辑。 2. **`getAction() == MotionEvent.ACTION_DOWN`** - 判断用户的行为是否是一个&ldquo;按下&rdquo; (`ACTION_DOWN`) 动作。这是典型的触摸交互起点,通常表示一次新的点击开始。 3. **`isButtonPressed(MotionEvent.BUTTON_PRIMARY)`** - 验证是否有鼠标的主要按键(通常是左键)被按下。这意味着只对鼠标左键的有效按下做出反应。 4. **`isOnScrollbarThumb(...)`** - 这是对特定 UI 区域的一个验证函数,传入的是鼠标指针的位置坐标 `(x, y)`。如果这个点落在滚动条的滑块部分内,则认为应该处理该事件。 5. **最终结果** - 当所有条件都成立时,说明这是一个来自鼠标的有效按下操作并且发生在滚动条滑块上,此时 ViewGrup 应当拦截事件;否则继续将事件交给子 View 或下一个处理器。 --- ### **核心机制理解** - **事件分发流程** 触摸事件从父容器到子组件的过程中会经历三个阶段:`dispatchTouchEvent()` &rarr; `onInterceptTouchEvent()` &rarr; 子级的 `onTouchEvent()`。其中 `onInterceptTouchEvent` 决定着父级是否会夺取控制权,从而中断向下传递的过程。 - **拦截规则设计目的** 此处的设计意图非常明显&mdash;&mdash;专门针对鼠标在滚动条上的精确交互加以优化管理。比如,在桌面应用风格下允许直接拖拽滚动条而不让其下的内容抢夺焦点或产生冲突行为。 --- ### **实际应用场景** 这种类型的事件拦截常见于复杂的布局结构中,例如包含多种手势支持的应用界面(地图缩放平移、列表上下翻页),或者模拟 PC 上滚轮效果的手势识别模块里都需要类似精细地调整哪些情况应由上级接管而不再往下层扩散出去。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值