首先多点触控要使用event.getActionMasked()来获取事件,调用情况如下:

  • case MotionEvent.ACTION_DOWN: //第一根手指按下触发,只会触发一次
  • case MotionEvent.ACTION_MOVE: //所有手指的move事件都会触发这个事件
  • case MotionEvent.ACTION_UP: //只会触发一次,最后一根手指抬起时触发
  • case MotionEvent.ACTION_POINTER_DOWN: //非第一跟手指按下触发
  • case MotionEvent.ACTION_POINTER_UP: //非最后一根手指抬起触发
    接下来看一段代码和效果
public class MultiTouchView extends View {private float offsetX, offsetY;private float lastOffsetX, lastOffsetY;private float downX, downY;Bitmap bitmap;Paint paint;float currentScale;private int currentPointId;。。。省略@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.test3);paint = new Paint();if ((float) bitmap.getWidth() / bitmap.getHeight() > (float) getWidth() / getHeight()) {//图片是横向图片currentScale = (float) getWidth() / bitmap.getWidth();} else {currentScale = (float) getHeight() / bitmap.getHeight();}}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.translate(offsetX, offsetY);canvas.scale(currentScale, currentScale, getWidth() / 2f, getHeight() / 2f);canvas.drawBitmap(bitmap, (getWidth() - bitmap.getWidth()) / 2f, (getHeight() - bitmap.getHeight()) / 2f, paint);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getActionMasked()) { //getAction//只会触发一次case MotionEvent.ACTION_DOWN:downX = event.getX();downY = event.getY();currentPointId=0;break;//所有手指移动都是触发这个事件case MotionEvent.ACTION_MOVE://获取id对应的index值,index是会变化的,id不会变化//int index= event.findPointerIndex(currentPointId);//移动距离:上次偏移值+当前滑动距离offsetX = lastOffsetX + event.getX() - downX;//event.getY() 使用的是pointerIndexoffsetY = lastOffsetY + event.getY() - downY;invalidate();break;//只会触发一次,最后一根手指抬起时触发case MotionEvent.ACTION_UP://抬手记录上次偏移值lastOffsetX = offsetX;lastOffsetY = offsetY;break;//非第一跟手指按下触发case MotionEvent.ACTION_POINTER_DOWN:break;//非最后一根手指抬起触发case MotionEvent.ACTION_POINTER_UP:break;}return true;}
}

自定义了一个view,onDraw绘制了一张图片,在ACTION_MOVE的时候offsetX(Y)达到图片随手指滑动的效果:

我这里的操作是

  1. 先在右上角按下手指1,滑动,图片能跟随手指滑动
  2. 接着在左下角按下手指2并滑动发现手指2没法滑动图片(依旧只会跟随手指1滑动)
  3. 然后松开手指1,这时候图片跳到左下角并能跟随手指2滑动了
  4. 最后再按下手指1,图片跳到了右上角并跟随手指1滑动

为什么第二步按下手指2没法滑动图片呢?来看MotionEvent.ACTION_MOVE中的代码:

offsetX = lastOffsetX + event.getX() - downX

问题就在这个event.getX(),查看MotionEvent 的源码:

第二个参数pointerIndex用的是默认值0,一番查阅后发现:
每根手指按下后系统都会保存该手指的index和id,移除一根手指后index会重新排序,原id不变。当插入一个手指时会根据id列表进行插入操作,如 下图:

当依次按下四根手指时四根手指的id和index相同,依次是0123,当移除第二根手指,那么将会重新排序,第三根手指的index变为1,id不变,第四根手指的index变为2,id不变。这时候再按下一个手指它会发现id只有0、2、3,于是生成了id为1的手指,然后重新排序变成跟最开始的状态一样。

回头看之前的操作,依次按下手指1和2时生成了两个:手指1(id=0,index=0),手指2(id=1,index=1)
因此,在上面的操作的第二步中,因为Action_move中event.getX() 始终用的index都是0,所以处理的都是第一根手指,第二根手指自然无法拉动图片;
第三步中,因为移除了第一根手指,进行了重新排序,手指2的index变成了0,所以手指2能拖动图片
第四步,手指1重新按下发现当前只有手指2(id=1),并没有id0,因此创建了一个手指id为0,再重新排序的时候变成了手指1(id=0,index=0),手指2(id=1,index=1),手指1的index为0,因此是手指1能拖动图片。

接下来实践一下,将上面的View改为:最后按下的手指拉动图片
思路:记录最后按下手指的id,根据手指的id获取index,ACTION_MOVE中event.getX/Y()传入index:

 case MotionEvent.ACTION_DOWN:downX = event.getX();downY = event.getY();currentPointId=0;break;//所有手指移动都是触发这个事件
case MotionEvent.ACTION_MOVE://获取id对应的index值,index是会变化的,id不会变化int index= event.findPointerIndex(currentPointId);//根据id获取index//移动距离:上次偏移值+当前滑动距离offsetX = lastOffsetX + event.getX(index) - downX;//event.getY() 使用的是pointerIndexoffsetY = lastOffsetY + event.getY(index) - downY;invalidate();break;//只会触发一次,最后一根手指抬起时触发case MotionEvent.ACTION_UP://抬手记录上次偏移值lastOffsetX = offsetX;lastOffsetY = offsetY;break;//非第一跟手指按下触发
case MotionEvent.ACTION_POINTER_DOWN:int pointerIndex= event.getActionIndex();currentPointId=event.getPointerId(pointerIndex);//解决跳动downX=event.getX(pointerIndex);downY=event.getY(pointerIndex);lastOffsetX = offsetX;lastOffsetY = offsetY;break;

在ACTION_DOWN时记录了当前id:currentPointId=0(因为是第一个手指id必然是0),在ACTION_POINTER_DOWN即非第一根手指按下的时候通过getActionIndex、event.getPointerId(pointerIndex)得到按下的id,最后在ACTION_MOVE事件中通过findPointerIndex(currentPointId)找到当前id的index,这样就保证了index为最后按下的手指index。
到此就实现了最后按下的手指拉动图片的效果,但是引入了新的问题:当拖动图片的那根手指抬起来后会出现闪退。
这是因为event.findPointerIndex(currentPointId)数组越界,因为手指抬起后currentPointId被移除了,通过这个id找index自然会报错。在ACTION_POINTER_UP中进行处理:

            //非最后一根手指抬起触发case MotionEvent.ACTION_POINTER_UP:int upIndex = event.getActionIndex();int pointerUpId = event.getPointerId(upIndex);if (pointerUpId == currentPointId) {//如果抬起的是最后一个手指if (upIndex == event.getPointerCount() - 1) {upIndex = event.getPointerCount() - 2;} else {upIndex++;}currentPointId = event.getPointerId(upIndex);//记录位置,解决跳动downX = event.getX(upIndex);downY = event.getY(upIndex);lastOffsetX = offsetX;lastOffsetY = offsetY;}break;

当手指抬起时获取手指id,如果id是正在控制拖动图片的手指id,那么如果该id是最后一个手指则将index回退一个(将拖动交给上一根手指处理),如果该id不是最后一个,那么index++,即交给下一根手指处理。
最后剩下新手指按下图片跳动的问题是因为手指按下时没有记录当前的downX(Y)和lastOffsetX (Y)。
完整代码---------------------------------------------------------------------------------------->

 import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;import androidx.annotation.Nullable;public class MultiTouchView extends View {private float offsetX, offsetY;private float lastOffsetX, lastOffsetY;private float downX, downY;Bitmap bitmap;Paint paint;float currentScale;private int currentPointId;public MultiTouchView(Context context) {this(context, null);}public MultiTouchView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public MultiTouchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.test3);paint = new Paint();if ((float) bitmap.getWidth() / bitmap.getHeight() > (float) getWidth() / getHeight()) {//图片是横向图片currentScale = (float) getWidth() / bitmap.getWidth();} else {currentScale = (float) getHeight() / bitmap.getHeight();}}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.translate(offsetX, offsetY);canvas.scale(currentScale, currentScale, getWidth() / 2f, getHeight() / 2f);canvas.drawBitmap(bitmap, (getWidth() - bitmap.getWidth()) / 2f, (getHeight() - bitmap.getHeight()) / 2f, paint);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getActionMasked()) { //getAction//只会触发一次case MotionEvent.ACTION_DOWN:downX = event.getX();downY = event.getY();currentPointId = 0;break;//所有手指移动都是触发这个事件case MotionEvent.ACTION_MOVE://获取id对应的index值,index是会变化的,id不会变化int index = event.findPointerIndex(currentPointId);//根据id获取index//移动距离:上次偏移值+当前滑动距离offsetX = lastOffsetX + event.getX(index) - downX;//event.getY() 使用的是pointerIndexoffsetY = lastOffsetY + event.getY(index) - downY;invalidate();break;//只会触发一次,最后一根手指抬起时触发case MotionEvent.ACTION_UP://抬手记录上次偏移值lastOffsetX = offsetX;lastOffsetY = offsetY;break;//非第一跟手指按下触发case MotionEvent.ACTION_POINTER_DOWN:int pointerIndex = event.getActionIndex();currentPointId = event.getPointerId(pointerIndex);//记录位置,解决跳动downX = event.getX(pointerIndex);downY = event.getY(pointerIndex);lastOffsetX = offsetX;lastOffsetY = offsetY;break;//非最后一根手指抬起触发case MotionEvent.ACTION_POINTER_UP:int upIndex = event.getActionIndex();int pointerUpId = event.getPointerId(upIndex);if (pointerUpId == currentPointId) {//如果抬起的是最后一个手指if (upIndex == event.getPointerCount() - 1) {upIndex = event.getPointerCount() - 2;} else {upIndex++;}currentPointId = event.getPointerId(upIndex);//记录位置,解决跳动downX = event.getX(upIndex);downY = event.getY(upIndex);lastOffsetX = offsetX;lastOffsetY = offsetY;}break;}return true;}
}

最终效果:

android多点触控的理解相关推荐

  1. Android多点触控详解

    本文转载自GcsSloop的 安卓自定义View进阶-多点触控详解 的文章 Android 多点触控详解,在前面的几篇文章中我们大致了解了 Android 中的事件处理流程和一些简单的处理方案,本次带 ...

  2. 模拟Android多点触控

    Android多点触控 Android多点触控 多点触控实现思路 第一种adb shell input方式 第二种adb shell sendevent方式 多点触控实现思路   经过资料的查询,要在 ...

  3. Android多点触控揭秘

    本文原创,转载请注明:http://blog.csdn.net/cloudzfy1/article/details/6582707 Google 暑期大学生博客分享大赛 - 2011 Android ...

  4. Android多点触控技术

    1 简介 Android多点触控在本质上需要LCD驱动和程序本身设计上支持,目前市面上HTC.Motorola和Samsung等知名厂商只要使用电容屏触控原理的手机均可以支持多点触控Multitouc ...

  5. Android 多点触控消息捕获与处理

    1 简介 Android多点触控在本质上需要LCD驱动和程序本身设计上支持,目前市面上HTC.Motorola和Samsung等知名厂商只要使用电容屏触控原理的手机均可以支持多点触控Multitouc ...

  6. android多点触控

    网上搜索后有很多的多点触控的东西,自己也写个吧,实现的就是在屏幕上画个圆角的矩形随着2点的大小而变换. 下面的东西是在网上找的一个例子然后自己更改的. View Code 1 package com. ...

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

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

  8. Android多点触控之ZoomImageView完全解析

    ZoomImageView是一个类似photoview的图片预览控件,实现了对图片的手势放大缩小平移,以及双击放大缩小解决和viewpager滑动冲突等功能,主要是通过GestureDetector, ...

  9. Android 多点触控 MotionEvent详解

    相关API 介绍 MotionEvent.getY() 和 MotionEvent.getRawY() 的区别 getY 表示触摸事件在当前的View内的Y 坐标, getRawY表示触摸事件在整个屏 ...

  10. Android多点触控MultiTouch浅析

    申明: 参考:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/0226/914.html 下面实现如何通过应用层支持多点触控操作, ...

最新文章

  1. Fish Detection
  2. Vue.js过滤器概述
  3. 如何通过调试的方式搞清楚Angular createEmbeddedView具体创建的UI元素是什么
  4. Java 8 Friday Goodies:Lambda和XML
  5. 从前,小夕种了一棵树
  6. 信息学奥赛一本通(1075:药房管理)
  7. 《项目百态:软件项目管理面面观》三模式总结
  8. 俄罗斯议会预计2021年代币发行将激增
  9. 让一让,神州泰岳要进化了
  10. 博客园php教程,PHP仿博客园,个人博客(1)_PHP教程
  11. 李航《统计学习方法》SMO算法推导中的思考
  12. python3.8下载request_python3 requests 安装包下载安装[windows]
  13. vue-router—12全局钩子函数
  14. 计算机考研作息时间表,2020考研的最佳作息时间表 如何安排学习时间
  15. U3D学习项目一:2D横版小狐狸闯关游戏(代码部分一)
  16. 磁盘管理压缩卷显示服务器异常,Win7分配盘符提示“磁盘管理控制台不是最新状态”错误怎么办...
  17. python足球数据可视化_欧洲足球,5大联赛!Python爬虫数据可视化带你解析经典赛事...
  18. Stegano之binwalk、C32Asm
  19. cgb2110-day01
  20. javascript中用三元运算符实现手动图片转换

热门文章

  1. 华硕计算机cpu怎么超频怎么设置,内存和CPU超频操作_华硕 ROG Rampage VI Apex_主板评测-中关村在线...
  2. retrofit 响应时间_HTTP Retrofit 网络传输
  3. 苹果备份有什么用_数据备份用什么软件好?好用的数据备份软件分享
  4. 2022年软件测试有哪些趋势?
  5. dota英雄技能快捷键大全
  6. SCI论文撰写——Conclusion
  7. 报警c语言程序,PIC单片机警报声C程序
  8. 什么样的条件能够满足游戏音效制作
  9. 麻将 java_java麻将游戏算法
  10. C++游戏编程-走迷宫详解