Android Touch事件传递机制

Touch事件传递机制,其实说起来还是比较复杂的,所涉及的内容和细节也都比较多。为了方便理解,本文将由浅入深的进行讲解。

首先要知道我们对于屏幕的所有操作,包括点击、放开、滑动,以及由这些基本操作组成的放大、缩小、旋转等操作全部是被封装在MotionEvent对象中进行操作的。我们需要通过getAction()判断是何种事件。这些事件包括如下6种:

ACTION_DOWN: 第一个点按下时触发

ACTION_UP: 屏幕上唯一的一个点抬起时触发

ACTION_MOVE: 当屏幕上的点移动时触发。

ACTION_POINTER_DOWN: 当屏幕上已经有一点按住,再按下其他点便会触发该事件。

ACTION_POINTER_UP: 当屏幕上有多个点被按住,松开其中的点时触发(非最后一个点,最后一个点触发ACTION_UP)。

ACTION_CANCEL:当前的手势被释放时会触发,当前手势指的是从ACTION_DOWN开始以及后面一系列的ACTION_MOVE、ACTION_POINTER_DOWN、ACTION_POINTER_UP操作。

到这里我们就可以写出屏幕触摸事件相应的代码了:

@Override
    public boolean onTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            // 第一个点按下去的相关处理
            break;
        case MotionEvent.ACTION_MOVE:
            // 手指在屏幕上移动相关处理
            break;
        case MotionEvent.ACTION_UP:
            // 屏幕上最后一个点离开屏幕时相关处理
            break;
        }
        return super.onTouchEvent(ev);
    }

只要把握这六种事件就可以了,是不是很简单呢?但是Touch事件并非这么简单,到这里还有很多问题没有搞清楚。Touch事件的事件源,处理者是谁?处理的具体方法有哪些?具体的流程如何?下面还请听详细分解。

Touch事件传递

Touch事件的处理分为三个层面:Activity,ViewGroup,View。我们所说的Touch事件传递便是在这三个层面之间进行传递的。而事件的传递,依靠的是三个方法dispatchTouchEvent()­­­----事件分派,onInterceptTouchEvent()----事件拦截,onTouchEvent()----事件处理。我们上面看到的示例代码中onTouchEvent()便是我们实际处理操作的方法。而至于事件是如何传递的,上面我们并不清楚。下表给出这三个层次具体的实例类和和这三个方法之间的关系。

层次

实例类

方法

Activity

 

dispatchTouchEvent, onTouchEvent

ViewGroup

RelativeLayout, FrameLayout, LinearLayout, 

AbsoluteLayout, ListView,ScrollView...

dispatchTouchEvent, onInterceptTouchEvent, 

onTouchEvent

View

Button, EditText, TextView, ImageView

dispatchTouchEvent, onTouchEvent 

表一 三个层次及其具体实例类和三个方法之间的对应关系

下面将通过一个示例来表现Touch事件究竟是如何在这三个层面之间进行传递的。我们拿下面这张图来作为Touch事件传递的层次图。

图一 Touch事件传递涉及层次图

所有的Touch事件一定都是从ACTION_DOWN这个事件开始的,那么当你按下屏幕那一刻开始,也就是触发了ACTION_DOWN这个事件。Touch事件传递便开始工作了。以上面这张图为例。

当ACTION_DOWN被触发,系统会调用Activity的dispatchTouchEvent方法,对该事件进行分发,然后将事件分发到RelativeLayout的dispatchTouchEvent方法进行处理。RelativeLayout会调用它的onInterceptTouchEvent方法判断是否要拦截下这个事件,然后自己处理。如果返回true那个执行RelativeLayout的onTouchEvent方法,如果返回false那么这条传递链就继续向下延伸到RelativeLayout的子View –TextView的dispatchTouchEvent,由于TextView已经不能够有子View了,不能够再向下传递,dispatchTouchEvent再将事件分发到TextView的onTouchEvent方法,onTouchEvent返回true或者false:

1)     如果onTouchEvent返回true,表示TextView能够处理该事件,那么事件就不再传递下去,后续的事件(ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP,ACTION_UP)都会按照同样的传递过程进行传递,最后交给TextView的onTouchEvent方法进行处理。

2)     如果onTouchEvent返回false,表示TextView不能够处理该事件,这时事件就会发生回传,传递给其父View– RelativeLayout的onTouchEvent方法,如果onTouchEvent方法返回true,表示RelativeLayout可以处理该事件,那么后续的事件传递到RelativeLayout的onInterceptTouchEvent方法的时候就会拦截下来直接由RelativeLayout的onTouchEvent进行处理;如果onTouchEvent方法返回false,那么事件继续进行上传到Activity的OnTouchEvent,如果返回true由它进行处理,如果返回false,由于它已经是最顶层了,事件传递到此为止,Touch事件无效。

说了这么多,不如来一幅生动形象的图来描述整个的Touch事件传递过程吧。


上面两幅图分别表现的是1)和2)的事件传递图,实线表示ACTION_DOWN事件的传递,虚线表示后续其它事件的传递。第一张图中TextView的onTouchEvent处理该事件,那么第二次仍然按照原路传递到TextView由它进行处理;第二张图中TextView的onTouchEvent不能处理该事件,那么就回传到RelativeLayout的onTouchEvent进行处理,可以处理便不进行回传,后续其它事件再传递,传递到RelativeLayout就由它来进行处理,不需要再向下传递。

到这里Touch事件传递机制的说明就算完成了。但Touch事件仍有很多让人疑惑不解的, 比如ACTION_MOVE拖动的方向距离是如何实现的, ACTION_POINTER_UP, ACTION_POINTER_DOWN有是如何实现的。下面在对它们进行简要的讲解。

ACTION_MOVE拖动方向距离是通过MotionEvent的getX() getY(), getRawX()getRawY 这四个方法得到的。这里值得一提的是前面两个方法是得到的是相对于当前Widget左上角的X, Y坐标,而后面两个方法得到的是以手机屏幕左上角为原点的X, Y      坐标。既然得到了当前坐标那么拖动的距离方向就很好计算了,通过当前ACTION_MOVE事件得到的X,Y坐标减去上一个事件(可能是ACTION_DOWN也可能是ACTION_MOVE)得到的X, Y坐标就可以得知拖动的方向距离了。

而ACTION_POINTER_UP,ACTION_POINTER_DOWN的实现则是通过方法getX(pointerIndex)实现的,pointerIndex表示的就是屏幕上面的点,这样我们就可以知道屏幕上的每个点的当前坐标了。

另外你有没有发现,Touch事件传递和DOM事件捕获和事件冒泡有着异曲同工之妙。
  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值