view的事件分发机制不仅仅是核心知识点更是难点,当view遇到滑动冲突或者其他冲突事件的时候,它的解决方法的理论基础就是事件分发机制,这章就来学习下view的事件分发机制
在了解分发机制之前,我们需要了解下一个对象,MotionEvent,就是一系列的监听view的状态的对象,其实点击事件的分发,就是MotionEvent的分发过程,当一个MontionEvent对象产生之后,系统需要把这个事件传递给一个具体的view,这个传递的过程就是分发过程,它有三个很重要的方法组成:dispatchTouchEvent,onIntercepTouchEvent和onTouchEvent,下面来介绍下这三个方法
dispatchTouchEvent
用于进行事件的分发,如果事件能够传递给当前的view,那么这个方法一定会被调用,返回的结果受当前view的onTouchEvent和下级view的dispatchTouchEvent方法的影响,返回true,则由当前view进行事件处理,则当前view的onTouchEvent方法会被调用,false则往下分发,注意的是,如果当前的view是顶级view,则由Activity处理,如果不是顶级view,则由顶级view去处理,默认情况下会由当前的view处理
onIntercepTouchEvent
用来判断是否拦截某个事件,true表示拦截,false表示不拦截,如果当前的view拦截了某个事件,那么在同个事件序列之中,则不会再次调用此方法,也就是说,如果我拦截了滑动事件,那么当再有滑动事件的时候,这个方法不会再次被调用,自动拦截,不拦截事件的话,则会继续往下传递,默认情况下会拦截,由当前的view处理
onTouchEvent
用来处理事件,在dispatchTouchEvent方法中调用,返回结果是否处理当前事件,如果不处理,则在同个事件的序列中,当前的view无法再次接受到该事件,如果返回true,则处理该事件,如果返回false,则事件会从当前的view往上传递,默认情况下会处理事件,如果都不处理该事件,那该事件则会“消失”,并且接受不到下一次事件
三者关系
我们知道这三个方法是干嘛用之后,我们来看看他们的关系,假设现在有个xml布局,里面只有一个Button,我们给Button添加点击事件,那么当点击事件发生之后,首先会传递到顶层view,这时候顶view(也叫根ViewGroup)的dispatchTouchEvent方法就会被调用,由它来决定事件的分发,如果顶view的onIntercepTouchEvent返回true,则表示它要拦截这个点击事件,就不会再往下传递,就交给了它的onTouchEvent方法处理;如果是false,则表示它不拦截这个点击事件,就继续往下传递,到达它的子view,然后子view的dispatchTouchEvent方法被调用,然后继续判断是否需要进行事件分发,以此类推下去
这里要注意的地方有两个:
1,如果我们的view设置了onTouchListener之后,那么onTouchListener中的onTouch方法会优先被调用,这时候的事件处理还得看onTouch的返回结果,如果是false,则当前view的onTouchEvent直接就被调用了,true则不会被调用,在像上面那样进行分发,由此可见,onTouchListener的优先级比onTouchEvent要高
2,当一个view的事件触发后,它传递的过程是:Activity——>Window——>顶层view,顶层view接受到事件后,就会根据事件分发机制去传递,如果所有的view都不处理这个事件,那么这个事件就会传递回给Activity,Activity的onTouchEvent的方法会被调用,这个过程很好理解,举个简单的例子,假如点击事件是个任务,这个任务由项目经理安排下来给某个程序员做(这个就相当于事件分发),结果这个程序员搞不得(onTouchEvent返回false),那怎么办?任务得完成啊,难题得解决,这时候就需要能力强的程序员出马了(上级的onTouchEvent被调用),如果还是不行,就一级一级往上推,最后都不行的话,那就只能项目经理出马了,如果项目经理也搞不得,改需求吧~~~
总结
1,同个事件顺序是从手指触摸屏幕那一刻开始,到手指离开屏幕那一刻结束
2,正常情况下,一个事件只能被一个view拦截,因为一旦一个view拦截了某个事件,那么同个事件序列都会直接交给它处理,但也可以通过特殊手段处理,比如view可以将本应该是自己处理的事件再通过onTouchEvent强行传递给其他view处理
3,view一旦拦截某个事件后,onIntercepTouchEvent不会再次被调用,也就是说系统不会再去询问它是否还要拦截,而是直接就交个它处理,这里注意的是,必须是同个事件,而不是说我拦截了点击事件,然后会自动拦截其他事件
4,view一旦拦截某个事件后,必须处理掉该事件,否则当有事件来的时候,会重新由顶view重新分发,比如说项目经理交个你任务,你还没做完,那么项目经理不会再将其他任务交给你
5,默认不拦截任何事件下,onIntercepTouchEvent默认返回false
6,如果view没有onIntercepTouchEvent方法,一旦有点击事件传递给它,它的onTouchEvent方法会被调用
7,view的onTouchEvent方法默认会处理掉事件(返回true),除非它不可以点击(clickable和longClickable都是false),默认情况下,view的longClickable返回false,clickable属性要分情况,比如Button默认的是true,TextView默认是false
8,view的enable属性不会影响onTouchEvent默认的返回值,只要它的clickable或者longClickable有一个是true,那么它的onTouchEvent默认就是返回true
9,事件传递过程是由外向内传递,总是先从顶view开始,一级一级往下传递
好了,这篇文章就先简单介绍下事件分发机制,下篇在深入去了解