Android中的触摸事件——MotionEvent中的多点触控

Android中的触摸事件——MotionEvent中的多点触控,第1张

触摸事件在Android手机中有多重要不言而喻,用户的每次 *** 作都和它有关。不知道大家有没有见过一些自定义的控喊烂春件有这样的问题:当单手 *** 作的时候,没有问题,但是当第二根手指头放上去的时候,该View中的内容就会“跳动一下”,如果有这样问题的控件,就是没有处理多点触控。该篇内容主要讲解MotionEvent对象中的多点触控信息,以及RecyclerView对于这种多点触控是如何处理的。MotionEvent又是啥呢?用来记录用户在屏幕中的触摸信息的对象。假如你点了一下屏幕(假如你手没抖,而且速度很快),这个时候就会产生两个MotionEvent对象(UP和DOWM)。

一次完整的触摸事件流(官方叫gesture)至少包括ACTION_DOWN和ACTION_UP两个Event(手指触摸的情况,不考虑使用鼠标的情况,本文后面所描述的所有情况都是手指触摸的情况)。前面提到了Event的ACTION,我们一般有两个方法可以取到ACTION,一个是 getAction() ,还有一个就是 getActionMasked() 。这两个方法有什么区别呢?action中包含了Pointer的Index,而actionMasked中不包含这个Index。那什么又是Pointer呢?这就涉及到该篇内容要重点讨论的多点触控。可以理解成每一个触控点,通俗点讲就是你放在屏幕上的手指头。我们一般都用ActionMasked这个历扒方法来拿这些Action。下面就简单来说明一下这些常见的Event。

第一根手指头触摸到屏幕(之前屏幕上没有手指头),一次事件触摸流的开始,很简单,但是很重要,这里也要简单的提一下,在ViewGroup中也是根据这次事件的坐标来决定该次事件流交给谁来处理,直到这次事件流完成(ACTION_UP)。

就是你的手指头在屏幕上滑动,就会产生这个事件。

最后一根手指头离开屏幕(屏幕上没有手指头了),标志着该次事件流已经完成。

这次事件流被取消了,虽然还没有完成,一般是ViewGroup经过某种条件判断会设置这样的ACTION。

当屏幕上已经有手指头郑耐的时候,再按一个手指头下去就会触发这个事件。

当手指头离开屏幕,同时屏幕上还有手指头的时候就会触发这个事件。

如果你的自定义控件处理好了上面的6种ACTION,那么你的控件对触摸的处理就很好了,因为RecyclerView就只是处理了这6种Event。

在一个MotionEvent对象中,包含了你在屏幕上所有的触摸点信息,他默认会有一个类似于active的触摸点,可以通过方法 getActionIndex() 拿到这个触摸点的Index,然后再通过方法 getPointerId() 能拿到这个触摸点的Id,Id通过 findPointerIndex() ,能再拿到这个Index。这里需要注意的是在一次事件流中,同一个触摸点的Index是可能发生改变的,但是Id是不会改变的。在方法 getX() 和 getY() 中都可以传一个Index来拿你想要的触摸点的坐标,不止这两个方法可以传入index,其他的读者自己去研究了。下面我们来讨论下不同情况下active的默认触摸点都是哪些点呢?

这些ACTIONs默认的active触摸点Index都是0,也就是说这些事件如果你的初次点击屏幕的手指头没有离开屏幕,那就一直是这个点,如果这个手指头已经离开屏幕,那这个点就变成了第二个点击屏幕的点,依次类推。

默认active触摸点是新点击到屏幕上的那个点,但是在后续的move中这个默认index又回变成0。这里也可以简单解释下文章开篇中提到的“跳一下”的Bug:因为在第二个手指头点击屏幕的瞬间,active的触摸点为第二个手指头,这个时候默认的坐标也是第二个指头,后续的move事件中默认的active触摸点又会变成第一个手指头,所以会出现跳一下的Bug。

这个Event和ACTION_POINTER_DOWN类似,只是默认的active的Index变成了离开屏幕的那个触摸点。

下面我们来看看RecyclerView中是如何来处理多点触控的。

这里简单说明下:一个手指到滑动就不说了,当屏幕上有新的手指加入时(之前屏幕上已经有手指头了),这个新加入的手指就会接管RecyclerView的滑动。当有手指头离开屏幕时(屏幕上还有其他的手指头),这个时候如果离开的手指头刚好时接管滑动的那个手指头,这个时候就会找index为0或着1的手指头重新接管滑动;如果离开的不是接管滑动的手指头,就不用管。

到这里多点触控相关的内容就没了,如果有错误的地方,欢迎大家指出来。后面可能还会有触摸事件的发送和滚动相关内容。

这是一个外层的控件,它是一个viewPager,在它的里面有个listView,listView每一个item被点击会d出内容,这里要讲解的是ViewPager子View滑动事件冲突的解决,安枯尘卓系统提供给我们关于触摸传递事件有三个方法:

它们分别是:

1、public boolean dispatchTouchEvent(MotionEvent ev)  这个方法用来分发TouchEvent

2、public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent

3、public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent

当条目被点击,首先Activity将TouchEvent事件通过 dispatchTouchEvent 方法传递给ViewGroup,

ViewGroup通过 dispatchTouchEvent 方法传递给 interceptTouchEvent, 这个时候,如果返回true ,则交给这个ViewGroup的onTouchEvent处理;如果返回false,则交给子View的dispatchTouchEvent方法处理。

当山森事件传递到子view 的dispatchTouchEvent方法中时,通过方法传递到当前View的onTouchEvent方法中,这个时候如果返回true,那么这个事件就会止于该view;如果返回 false ,那么这个事件会从这个子view 往上传递,而且都是传递到父View的onTouchEvent 来接收。

当传递到ViewGroup的 onTouchEvent 最后也返回 false 的话,它将继续传递到Activity的onTouchEvent中,还是返回false的话,这个事件就会“消失“;事件向上传到中间的任何没唯禅onTouchEvent方法中,如果返回true,则代表事件被消费,就不会再传递。

下附图给予参考,触摸传递:


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/12475520.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-25
下一篇 2023-05-25

发表评论

登录后才能评论

评论列表(0条)

保存