Android多点触控之——MotionEvent(触控事件)

今天晚上刚学习了一个多点触控的小程序,后面想对其做一个定制。在写的时候遇到很多问题,于是乎就查了一下API文档,又到网上查了一下高手的文章,最后自己又实践了一下。终于把多点触控事件监听的大概原理给弄清楚了。下面就写一下我个人对多点触控原理的理解:

一、MotionEvent事件的分类

      触控分为两类:单点触控多点触控

      1、如何获取触控事件信息?

        安卓中使用32位(int)来存储触控事件的动作信息触控索引。高16位暂时不用,后16位中高8位存储触控信息,低8位存储动作信息。

        在安卓当中,使用ACTION_MASK、ACTION_MASK_SHIFT、ACTION_POINTER_INDEX_MASK、ACTION_POINTER_INDEX_SHIFT这四个属性来获得触控事件信息。

        属性说明:

         ACTION_MASK = 8(0x00ff)  :动作信息掩码,用于截取目标动作信息;

         ACTION_MASK_SHIFT = 8(0x00ff) : 截取动作信息时所需移位个数

         ACTION_POINTER_INDEX_MASK =65280(0xff00) :高8位的位置信息掩码,用于截取索引信息

         ACTION_POINTER_INDEX_SHIFT= 8(0x00ff) :截取触控索引时所需的移位个数

        如果我们想要获取当前触控的全部信息,则使用

                        getAction();返回的是触控的所有信息

        如果我们仅仅需要获取当前触控的动作信息,则使用

                        getActionMasked();返回当前触控的动作信息,即低8位的信息

        如果我们想要获取的是当前触控的索引(比如:当你要监听是哪一个手指离开屏幕)

                        getActionIndex();可以达到效果,返回当前触控动作的索引

      2、如何区别动作类型?

          在一般的单点触控事件当中,我们只需要使用getAction()得到动作类型,再用ACTION_UP、ACTION_DOWN区分就可以达到目的。但是在多点触控的时候,则需要我

         们使用getActionMasked()获得动作信息,然后再区分动作是属于那一类。

         动作类型:

         ACTION_DOWN  :   第一个手指按下

         ACTION_UP    : 最后一个手指离开

         ACTION_POINTER_DOWN :非第一个手指按下

         ACTION_POINTER_UP : 非最后一个手指离开

         ACTION_POINTER_1_DOWN : 这是之前SDK版本所使用的,表示第一个手指按下,它的数值跟ACTION_DOWN是相等的

       ACTION_POINTER_2_DOWN:第二根手指按下

       ACTION_POINTER_3_DOWN:第三根手指按下

       ACTION_POINTER_x_DOWN:第x根手指离开

       原理:

         取mAction(触控信息)低8位,屏蔽高8位;

         即: actionType = (ACTION_MASK&mAction);

         例如:mAction= 0x0105H  (表示索引为1动作为:ACTION_DOWN,第一个手指按下)

         则:actionType= (0x00ff&0x0105)  = 5 = ACTION_DOWN;

 

   3、如何知道是哪个手指离开?

      如果在单点触控的情况下,监听离开直接使用ACTION_UP即可。但如果在多点触控的情况下,就需要我们定位是哪一个手指离开。这个使用就需要使用到getActionIndex()来获取触控动作的索引。从而得知是哪一个点离开了或者哪一个点按下了。

      其实getActionIndex()的实现原理很简单:

       取mAction(触控动作)高8位信息,然后再右移8位得到索引。

      即: Index = (ACTION_POINTER_INDEX_MASK&mACTION)>> ACTION_POINTER_MASK;

       例如:mAction = 0x0105H  (表示索引为1动作为:ACTION_DOWN,第一个手指按下)

       则:index= (0xff00&0x0105) >> 0x00ff = 1;

二、MotionEvent示例

   监听触摸事件(触摸每个点,以点为圆心生成一个不同颜色的小圆和一个交叉的十字,)

示例代码:

[java]  view plain  copy
  1. @Override  
  2.    public boolean onTouchEvent(MotionEvent event) {  
  3.      // TODO Auto-generated method stub  
  4.      int pointerCount = event.getPointerCount();  
  5.      if (pointerCount > MAX_TOUCHPOINTS) {  
  6.         pointerCount = MAX_TOUCHPOINTS;  
  7.      }  
  8.      // 锁定Canvas开始进行相应的界面处理  
  9.      Canvas c =getHolder().lockCanvas();  
  10.      if (c != null) {  
  11.         c.drawColor(Color.BLACK);  
  12.         // 事件类型,也可以使用getActionMasked效果一样  
  13. //      int actionType = event.getAction()& MotionEvent.ACTION_MASK;  
  14.             int actionType = event.getActionMasked();  
  15.         switch (actionType) {  
  16.         case MotionEvent.ACTION_DOWN:  
  17.           // 第一个点被按下  
  18.           Toast.makeText(getContext(), "第一个点被按下", Toast.LENGTH_SHORT)  
  19.                .show();  
  20.           Toast.makeText(getContext(), "ACTION_POINT_DOWN",  
  21.                Toast.LENGTH_SHORT).show();  
  22.           // 现在屏幕上画一个十字,横向贯穿屏幕,纵向贯穿屏幕  
  23.           //获得触控事件的索引,通过索引获得Pointer的ID  
  24.           int id = event.getPointerId(event.getActionIndex());  
  25.           Toast.makeText(getContext(), "id = " + id, Toast.LENGTH_SHORT)  
  26.                .show();  
  27.           int x = (int) event.getX();  
  28.           int y = (int) event.getY();  
  29.           drawCrosshairsAndText(x, y, touchPaints[id], 0, id, c);  
  30.           drawCircle(x, y, touchPaints[id], c);  
  31.           break;  
  32.         case MotionEvent.ACTION_UP:  
  33.           // 最后一个点被释放  
  34.           Toast.makeText(getContext(), "最后一个点被释放", Toast.LENGTH_SHORT)  
  35.                .show();  
  36.           break;  
  37.         case MotionEvent.ACTION_POINTER_DOWN:  
  38.           // 非第一个点被按下  
  39.           Toast.makeText(getContext(), "非第一个点被按下", Toast.LENGTH_SHORT)  
  40.                .show();  
  41.           // 现在屏幕上画一个十字,横向贯穿屏幕,纵向贯穿屏幕  
  42.           for (int i = 0; i < pointerCount; i++) {  
  43.              // 获取一个触点的坐标,然后开始绘制  
  44.              int id1 = event.getPointerId(i);  
  45.              int x1 = (int) event.getX(i);  
  46.              int y1 = (int) event.getY(i);  
  47.              drawCrosshairsAndText(x1, y1, touchPaints[id1], i, id1, c);  
  48.           }  
  49.    
  50.           // 使用不同的颜色在每个手指的位置画圆  
  51.           for (int i = 0; i < pointerCount; i++) {  
  52.              int id1 = event.getPointerId(i);  
  53.              Toast.makeText(getContext(),"id = " + id1,  
  54.                   Toast.LENGTH_SHORT).show();  
  55.              int x1 = (int) event.getX(i);  
  56.              int y1 = (int) event.getY(i);  
  57.              drawCircle(x1, y1, touchPaints[id1], c);  
  58.              // DrawCircleRun drawCircleRun = new  
  59.              // DrawCircleRun(x,y,id,c);  
  60.              // mRunList[event.getActionIndex()] = drawCircleRun;  
  61.              // mThreadPool.execute(drawCircleRun);  
  62.           }  
  63.           break;  
  64.         case MotionEvent.ACTION_POINTER_UP:  
  65.           // 非最后一个点被释放  
  66.           //获得释放的点的索引和ID  
  67.           int point_index = event.getActionIndex();  
  68.           int point_id = event.getPointerId(point_index);  
  69.           Toast.makeText(getContext(), "非最后一个点被释放:"+"index ="+point_index+"   id = "+point_id, Toast.LENGTH_SHORT)  
  70.                .show();  
  71.           break;  
  72.         case MotionEvent.ACTION_MOVE:  
  73.           Toast.makeText(getContext(), "手指移动", Toast.LENGTH_SHORT).show();  
  74.           // 现在屏幕上画一个十字,横向贯穿屏幕,纵向贯穿屏幕  
  75.           for (int i = 0; i < pointerCount; i++) {  
  76.              // 获取一个触点的坐标,然后开始绘制  
  77.              int id1 = event.getPointerId(i);  
  78.              int x1 = (int) event.getX(i);  
  79.              int y1 = (int) event.getY(i);  
  80.              drawCrosshairsAndText(x1, y1, touchPaints[id1], i, id1, c);  
  81.           }  
  82.    
  83.           // 使用不同的颜色在每个手指的位置画圆  
  84.           for (int i = 0; i < pointerCount; i++) {  
  85.              int id1 = event.getPointerId(i);  
  86.              Toast.makeText(getContext(),"id = " + id1,  
  87.                   Toast.LENGTH_SHORT).show();  
  88.              int x1 = (int) event.getX(i);  
  89.              int y1 = (int) event.getY(i);  
  90.              drawCircle(x1, y1, touchPaints[id1], c);  
  91.              // DrawCircleRun drawCircleRun = new  
  92.              // DrawCircleRun(x,y,id,c);  
  93.              // mRunList[event.getActionIndex()] = drawCircleRun;  
  94.              // mThreadPool.execute(drawCircleRun);  
  95.           }  
  96.           break;  
  97.         case MotionEvent.ACTION_SCROLL:  
  98.           Toast.makeText(getContext(), "手指滑动", Toast.LENGTH_SHORT).show();  
  99.           break;  
  100.         case MotionEvent.ACTION_POINTER_2_DOWN:  
  101.           Toast.makeText(getContext(), "第二个手指按下", Toast.LENGTH_SHORT)  
  102.                .show();  
  103.           break;  
  104.         case MotionEvent.ACTION_POINTER_3_DOWN:  
  105.           Toast.makeText(getContext(), "第三个手指按下", Toast.LENGTH_SHORT)  
  106.                .show();  
  107.           break;  
  108.         case MotionEvent.ACTION_POINTER_3_UP:  
  109.           Toast.makeText(getContext(), "第三个手指离开", Toast.LENGTH_SHORT)  
  110.           .show();  
  111.           break;  
  112.         default:  
  113.           break;  
  114.         }  
  115.      }  
  116.      // 画完后,解锁显示  
  117.       getHolder().unlockCanvasAndPost(c);  
  118.      return true;  
  119. }  


三、为什么要使用掩码和位操作?

   很多人,我一开始也疑惑,为什么不从一开始就使用两个整型来存储动作和索引信息呢。这样不是更容易让人理解吗?不过看了API文档的解释之后,才明白这是为了节省内存。因为动作就那么几个,位置信息在高八位以上,还有24位的信息用来存储索引信息(2的24次方个点,绝对够用!)。因此只需要一个32位的整型就可以存储这两个信息。而且计算机内部也只是识别 0\1序列的,我们搞IT的免不了会接触到一些汇编,汇编语言里面的知识在这里就派上用场了,比如:移位、按位逻辑运算等知识。而且熟悉了位存储之后,对于Android的其他类别属性的理解也会更加有帮助。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Android多点识别是指Android设备可以同时检测并响应多个触摸点的能力。在触摸屏上,用户可以使用多个手指或触控笔来实现不同的手势和操作。 Android提供了多种多点识别的API,其中最常用的是通过MotionEvent类来实现。MotionEvent类提供了相关的方法来获取触摸事件的信息,如触摸点的数量、坐标、压力等。 在处理多点触摸事件时,我们可以通过判断触摸点的数量来执行不同的操作。例如,如果触摸点的数量为1,我们可以处理单点触摸操作,如滑动、点击等;如果触摸点的数量大于1,我们可以处理多点触摸操作,如缩放、旋转等。 另外,Android还提供了GestureDetector类和ScaleGestureDetector类来帮助开发者处理常见的手势操作,如滑动、缩放、旋转等。这些类封装了一些处理手势操作的算法,可以简化开发者的操作。 总的来说,Android多点识别功能让开发者可以更加灵活地处理用户的触摸操作,提供更丰富的交互体验。开发者可以利用Android提供的API和类库来实现各种复杂的手势操作,并为用户提供更加便捷和直观的操作方式。 ### 回答2: Android多点触控是指在一台Android设备的屏幕上,可以同时识别和响应多个手指触摸的操作。这项技术的引入,使得用户可以使用多指操作来进行各种操作,提供了更加丰富和灵活的交互方式。 Android多点触控主要通过以下几个关键技术来实现: 1. 坐标追踪:Android设备的屏幕使用坐标系统来标识不同的位置。在多点触控中,系统需要追踪每个手指的位置,并将其与具体的操作关联起来。通过使用触摸事件监听器和坐标系统,Android系统可以追踪并记录每个手指的位置信息。 2. 事件分发:当多个手指同时触摸屏幕时,操作系统需要分发并处理这些触摸事件Android系统使用事件分发机制将触摸事件传递给正在活动状态的应用程序或视图。事件分发机制根据触摸位置、手指动作等因素来决定如何分发和处理触摸事件。 3. 手势识别:Android系统还提供了一系列用于识别各种手势的内置算法和工具。通过这些工具,Android应用程序可以检测和识别手势,例如双击、滑动和缩放等操作。这些手势识别功能可以增强用户体验,并提供更加直观和自然的多点触控交互方式。 总之,Android多点触控技术为用户提供了更加丰富和灵活的交互方式。通过追踪和记录手指位置、事件分发和手势识别等关键技术,Android系统可以实现多点触控,并且应用程序可以根据这些触摸事件进行相应处理。多点触控的引入使得用户可以使用多指操作,更加方便地进行各种操作,提升了用户的体验和操作效率。 ### 回答3: Android多点触控是指设备支持同时识别并处理多个触摸点的能力。多点触控在现代智能手机和平板电脑上被广泛应用,使得用户可以利用多指手势来实现更多的操作和交互方式。 Android系统通过使用触摸屏硬件和软件驱动程序来实现多点触控。触摸屏硬件会感知用户的触摸动作,并将触摸点的坐标和压力信息传递给操作系统。软件驱动程序则负责解析和处理这些信息,并将其传递给应用程序。 Android系统在多点触控方面提供了丰富的支持和功能。用户可以通过同时使用多个手指在屏幕上进行操作,例如缩放、旋转、拖动等。这些手势都可以通过Multi-touch事件来捕获和处理。开发者可以在应用程序中使用Multi-Touch API来实现多点触控的交互效果。 在Android开发中,常用的Multi-Touch API包括MotionEvent类和GestureDetector类。MotionEvent类提供了用于处理单个触摸点和多点触摸的方法和常量。GestureDetector类则提供了用于检测和处理手势的方法和回调。 总结来说,Android多点识别能力使得用户可以通过多指手势来进行更自由、更灵活的操作和交互。开发者可以利用相关的API来实现多点触控的功能,并提升应用程序的交互体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值