在早期,非常多博客在讲解和控件交互的时候,只会关注:
ACTION_DOWN , ACTION_MOVE , ACTION_UP, ACTION_CANCEL
这样的控件在一个手指交互的时候基本没有问题,但是一旦两个手指甚至多指操作,一个支持上下滑动的控件就会有跳跃感。
那么今天的问题是:
- 支持多个手指以上的操作,还应该关注哪些事件?
- Google 官方的控件,比如 ScrollView,ViewPager 这些都是支持多指操作的,那么多个手指时,如何判断哪一个是 active pointer(需要考虑一个接一个按下;一个接一个抬起)。
- 一个未支持多指的控件,如何快速的支持?
以上问题,知道任意一个都可以回答。
另外,我们的问答数量已经突破了 50+,现在已经独立为 tab 啦,抬头即可看间。
本站始终追求非常高质量的提问,保证大多数问题能寻找答案的伙伴有所收获,么么哒,这个问题我觉得可以挂 5 天。
更多问答 >>
-
每日一问 | 控件不都是矩形么?遇到多边形,这个怎么绘制,事件分发怎么处理嘞?
2019-11-13 01:08 -
每日一问 | Kotlin 中不需要写“ ; ”,但是有个场景意外?
2019-11-22 00:12 -
2019-11-22 00:10
-
2019-11-26 00:12
-
每日一问 | Activity启动流程中,大部分都是用Binder通讯,为啥跟Zygote通信的时候要用socket呢?
2019-11-30 20:49 -
2019-11-03 23:50
-
2019-10-28 21:13
-
2019-10-23 00:10
-
2019-10-20 23:46
-
2019-10-15 23:26
之前做过一个小游戏,里面就有支持多指操作的需求。
那么,要支持多指操作,应该关注哪些事件?
在处理触摸事件的时候,除了基本的DOWN、MOVE、UP和CANCEL之外,还需要关注POINTER_DOWN和POINTER_UP这两个ACTION。
什么情况下的ACTION会是这两个呢?
先看一下它的文档描述:emmm,也就是非主要的指针(手指)按下或抬起的意思了。
这个 “非主要” 怎么理解?系统它是这样判定的:有一点要注意的就是,想要支持接收这两个ACTION,必须把event.getAction()
改为
event.getActionMasked(),当然了,也有
event.getAction() & MotionEvent.ACTION_MASK`这种写法,它们的效果是一样的。官方控件是怎么处理多指操作的呢?
就拿ScrollView来说吧。
它有一个叫mActivePointerId
的东西,用来记录当前活跃的指针,没错,同一时间内就算多只手指在做滑动手势,控件也只会响应mActivePointerId
所对应的指针坐标。ScrollView如何管理mActivePointerId?先看下它(精简后)的onInterceptTouchEvent
方法:可以看到:
当第一根手指按下时,会把它记录下来。
最后一根抬起时,会把
mActivePointerId
重置为无效。非主要手指抬起时,会先判断是不是当前活跃的手指抬起,如果不是的话,无需理会。如果是的话,就要重新指定另外一根手指作为活跃指针,并把原来的坐标改为新的活跃手指的坐标。(这样的话,即使活跃手指抬起了,也能无缝转换到另外一根手指上)
好,现在来看看
onTouchEvent
方法:大致逻辑也跟
可以看到,ACTION_MOVE的时候,获取事件坐标点(它这里只获取了y坐标没有x,是因为ScrollView只需要处理垂直滑动)时,并不是使用onInterceptTouchEvent
差不多,只是多了ACTION_MOVE和ACTION_POINTER_DOWN的处理。event.getX()/event.getY()
,而是调用了一个有参数的getY(int pointerIndex) 方法,这个方法会返回指定指针索引所对应的触摸点坐标。ACTION_POINTER_DOWN的时候,会直接拿这个新按下的非主要手指来当作当前活跃的手指,并且更新坐标值。好,来捋一下总体的流程:
ACTION_DOWN时(此前没有手指按下且没抬起),直接拿当前指针ID当作活跃ID
(情窦初开);ACTION_POINTER_DOWN时,又把新按下的手指当作活跃ID
(喜新厌旧);ACTION_MOVE时,会根据记录的活跃ID,来获取到对应的触摸点坐标;
ACTION_POINTER_UP时,如果刚好抬起的是当前活跃的手指,则指定另一根未抬起的手指当作活跃手指
(李代桃僵);ACTION_UP时,证明最后一根手指已抬起,重置活跃ID为无效;
ACTION_CANCEL,收到取消动作,处理方式和ACTION_UP一样;
如何快速支持多指操作?
看了下@找瓶子的汤猿同学提到的GestureDetector的源码,发现已经是支持了多指操作的,直接使用就行了,这是成本最低的方法;
还有就是,仿照ScrollView写一个咯,跟着上面分析过的流程来做,没有难度的。哈哈 小缘这个没有难度的,刺痛了我...
哈哈哈,我错了,有难度,有难度。。。
所以洗牙和多指触控是没关系的吧~
有关系,我们一般在进行多指触控的时候,都是两只手进行的(托手机那只手只有一只拇指是空闲的),如果不洗牙,久而久之牙齿就可能会有健康问题,比如说牙痛,一旦出现牙痛的时候,你就可能要用一只手去捂着,所以这 ...查看更多
有关系,我们一般在进行多指触控的时候,都是两只手进行的(托手机那只手只有一只拇指是空闲的),如果不洗牙,久而久之牙齿就可能会有健康问题,比如说牙痛,一旦出现牙痛的时候,你就可能要用一只手去捂着,所以这时候,是进行不了多指触控的。但如果洗了牙的话,牙齿就会很健康,不会牙痛,所以就不需要用手去捂着啦,这样就能用两只手进行多指触控了
没想到小缘居然还一本正经地解释洗牙和多指触控二者之间的关系。。。
尝试抛砖引玉哈
2 (多)手指(这里就写两个指头)按下会触发(重写onTouch注意要用event.getActionMasked()),以及index会复用,但是id不会(按下两个手指,id=0,1,index=0,1,,抬起第一个手指,id 1,index=0),所以要记录id,再用id找index确定手指移动
列举上述接力操作(最新的手指起作用),其余操作也一样,注意确定ponterId就好了定义trackingPointerId3 能想到的是常规操作可以复写GestureDetector来做
P(x, y, index, id)
x, y 是坐标index 是第几个手指, 这个值会变,会变。 作用:可以用来 遍历id 不会变,每一个 point 都有一个唯一的 idACTION_DOWN, ACTION_UP, ACTION_POINT_DOWN, ACTION_POINT_UP,均可以用 even.getActionIndex() 获得 index。(event.getPointerId(indext) 获得 id, getX(index), getY(index) 获得 x, y)
}
}*
为何 ACTION_MOVE 不能获得 index?
能获取,但值是 0,当你移动一个手指时,你能保证另外的手指没有抖动么,那么如何才能得到用户认为的那个动的手指呢? 没办法, 所以返回 0ACTION_POINT_DOWN, ACTION_POINT_UP 是第一手指之后的 DOWN 和 最后一个手指之前的 UP,用来支持多指 touch 的
要提的一点是,evnet.getAction() 不支持多指,event.getActionMasked() 才支持多点触摸,才会有 ACTION_POINT_DOWN, ACTION_POINT_UP
最后,便于理解,举个栗子
对于整个view的一系列事件ACTION_DOWN P(x, y, 0, 0)ACTION_MOVE P(x, y, 0, 0)ACTION_MOVE P(x, y, 0, 0)ACTION_MOVE P(x, y, 0, 0)ACTION_POINT_DOWN P(x, y, 0, 0), P(x, y, 1, 1)ACTION_MOVE P(x, y, 0, 0), P(x, y, 1, 1)ACTION_MOVE P(x, y, 0, 0), P(x, y, 1, 1)ACTION_POINT_UP P(x, y, 0, 0), P(x, y, 1, 1) // 抬起第一个手指ACTION_MOVE P(x, y, 0, 1) // 第二个手指 index 变为 0, id 不变ACTION_MOVE P(x, y, 0, 1)ACTION_UP P(x, y, 0, 1)原理理解了,项目中具体的逻辑就可以处理了
接管型: 如图片跟随手指移动,首先会跟随第一个手指移动,当第二个手指按下时接管图片的控制权,随后图片跟随第二个手指移动。 实现:记录当前控制图片移动的手指 id ,ACTION_POINT_DOWN ...查看更多
接管型: 如图片跟随手指移动,首先会跟随第一个手指移动,当第二个手指按下时接管图片的控制权,随后图片跟随第二个手指移动。 实现:记录当前控制图片移动的手指 id ,ACTION_POINT_DOWN 时 替换成第二个手指 相互协作型: 多个手指共同移动图片, 实现:通过遍历 index 获取多个手指的坐标平均值 各自为阵型: 比如画图软件,多指绘画,你画你的,我画我的,互不干扰 实现:通过 map 保存, key 为手指 id,value 为 path,然后通过 canvas.drawPath() 绘制
这个问题我觉得可以挂 5 天 这就是你懒得更新的理由吗
哈哈,已经更新50多个啦,不少了噢~
这个问题,就是常规控件哈,不是大家所理解的多指缩放什么的... 正常的下上滑动也应该支持多指~~
我突然觉得似乎缺少一个通知的功能,比如自己回复了一个问题或者回复了别人,要是自己忘了看,过几天都不知道自己回了那个了,现在问题不多还能找到,问题多了估计就找不到了,当然只是建议。 ...查看更多
我突然觉得似乎缺少一个通知的功能,比如自己回复了一个问题或者回复了别人,要是自己忘了看,过几天都不知道自己回了那个了,现在问题不多还能找到,问题多了估计就找不到了,当然只是建议。
我已计划做一个伪推送功能(轮询)的WanAndroid问答客户端,会周期性地抓取帐号回答过的问题(或关注的问题),并对比上次缓存的回复来实现(大概在下一篇文章写完之后开始)。 ...查看更多
我已计划做一个伪推送功能(轮询)的WanAndroid问答客户端,会周期性地抓取帐号回答过的问题(或关注的问题),并对比上次缓存的回复来实现(大概在下一篇文章写完之后开始)。
my dear dalao please daidaiwo