关于事件你应该知道的是
当一个事件产生后,他的传递过程遵循如下顺序Activity > Window > View
事件来源于activity,activity假如你没有重写任何关于事件纷发的方法的话,他会把事件传递给window,window将事件传递给decorView
现在我们来看下假如我们在activity中重写了dispatchEvent的方法是什么样的一个情况.
我们把activity中的dispatchTouchEvent 返回true
事件被activity的dispatchTouchEvent消耗掉,所以activity的
onTouchEvent方法得不到响应,我们看下log输出
很明显的能看出来,log只打印了dispatchTouchEvent中的相关方法,整个事件被dispatchTouchEvent消耗掉,并没有传递到我们的window > decorView 所有我界面的返回键接受不到事件,所以返回按钮的点击事件也没生效,
我们在把activity中的dispatchTouchEvent返回false看看是什么情况,,这也是我的一个疑问点,麻烦大神帮忙解答一下就是我activity中的dispatchTouchEvent返回了false,那么事件标志着事件没人处理,此时事件的根源是从activity来的,如果他都不管的话,这个事件已经不能返回他的父view ,当前activity的onTouchEvent()也无log输出,那么事件哪里去了????
然后我们看下返回false的log输出如下图:
log输出一只执行了activity中的dispatchTouchEvent的相关方法,
TouchEvent并没有任何输出,表明activity的onTouchEvent也没有接受到这个事件,此时我再点击返回键,的onclick依然是失效的,
所以.麻烦大神帮忙解答下这一点,当activity中的dispatchtouchevent返回false,事件的流程是怎么样的,???
最后我们让activity中的dispatchtouchevent 返回super看下
然后看下log日志的输出,以及log 的顺序,
注意log的顺序,dispatchTouchEvent down > onTouchEvent down
dispatchTouchEvent move > onTouchEvent move
dispatchTouchEvent up > onTouchEvent up
面试的时候注意面试官问的问题,和执行顺序的问题
然后我们往activity中加入一个linearlayout,我们重写一下linearlayout的有关事件的三个方法,并打印log看一下,暂时不往linearlayout中加入任何子view,单纯的看一下事件从activity传递到viewgroup的效果.
首先我们在书写一个TESTLinearlayout,如下
public class AAATestLinearlayout extends LinearLayout {
private static final String TAG = "AAATestLinearlayout";
public AAATestLinearlayout(Context context) {
super(context);
}
public AAATestLinearlayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AAATestLinearlayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Logger.e(TAG, TAG + ">>>>dispatchTouchEvent.ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Logger.d(TAG, TAG + ">>>>dispatchTouchEvent.ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Logger.w(TAG, TAG + ">>>>dispatchTouchEvent.ACTION_UP");
break;
}
// return true;
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Logger.e(TAG, TAG + ">>>>onInterceptTouchEvent.ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Logger.d(TAG, TAG + ">>>>onInterceptTouchEvent.ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Logger.w(TAG, TAG + ">>>>onInterceptTouchEvent.ACTION_UP");
break;
}
// return true;
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Logger.e(TAG, TAG + ">>>>onTouchEvent.ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Logger.d(TAG, TAG + ">>>>onTouchEvent.ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Logger.w(TAG, TAG + ">>>>onTouchEvent.ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
}
我们就先默认的让测试的linearlayout全部返回super值.
看下事件传递的过程从activity > window > decorView > 我们自己的linearlayout;
并且我们在linearlayout中的构造中设置了额外的onTouchLinstener,
我们看下的结果;
这里简答描述一下,我们往activity中加入了一个linearlayout.并且在构造中给linearlayoutset了一个touchlistener.
我们从log可以看到,事件从activity中开始传递,然后我们在linearlayout中有关事件的方法全部返回super.
其中关于onInterceptTouchEvent
我想说两句,这句话的返回值影响的是viewgroup容器中子view的事件传递,并不会对当前的viewgroup的onTouchEvent或者set 的touchlistener有影响,我们从log可以看出来,linearlayout的 onTouchEvent.down 和 touchliste的down均执行了
假如onInterceptTouchEvent的值返回的是super的话,我们看viewgroup的源码可以知道
默认是false,也就是不拦截…重要的是不拦截….
* appear here.
* </ol>
*
* @param ev The motion event being dispatched down the hierarchy.
* @return Return true to steal motion events from the children and have
* them dispatched to this ViewGroup through onTouchEvent().
* The current target will receive an ACTION_CANCEL event, and no further
* messages will be delivered here.
*/
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
这是viewgroup的源码,和Android艺术探索第143页第六条说的完全吻合,
还有一篇博客,应该是比较经典的,其中对onInterceptTouchEvent的解释如下;
这里博客博主说是返回super的话默认被拦截,并把拦截的事件交给当前view,处理,
我们这里的当前view就是我们的linearlayoutlayout 从log看确实执行了onTouchEvent.但是这个onTouchEvent并不是因为返回了super他没有拦截而执行了.因为笔者试着返回true false,super,对我们设置的touchlistener和onTouchEvent的down事件没有任何影响,
所以这块我也迷茫了半天,看了书本和咨询了群里的nil大概猜测一下可能是博主理解有出入或者笔误,再次留下博客的地址:请大神批阅和校正一下原文链接如下Android编程下的事件纷发
接着说我们的场景,目前我们linearlayout中的事件处理方法均没有对事件做处理,这样我们linearlayout中的子view比如我们的返回按钮确实能接收到事件,然后点击返回箭头,activity关闭,此事第一个场景走完.
这里以为linearlayout中dispatchonTouchEvent返回了true,事件在这里终止了,所以我们的返回箭头就接收不到事件,于是我们的返回按钮就失效了.
第二个场景,我们让linearlayout的dispatchonTouchEvent返回false,那么这个触摸事件将是一个怎么样的过程呢?
dispatchonTouchEvent.返回false,事件要被来自哪里,就要被返回哪里,假如我们的linearlayout还有父view ,那么这个事件将返回给父view的onTouchEvent事件处理,如果来自activity,那么将被activity的onTouchEvent处理,看下我们的log输出;
![这里写图片描述](http://img.blog.csdn.net/20160331173347685)
当我们点击我们的返回箭头的时候,因为事件从liearlayout中返回给了activity消费,所以子控件没法接收到事件,所以点击返回的箭头也无法生效;
因为事件也在activity中,并没有传递给子view 所以返回按钮失效
下一个场景,让我们的liearlayout中的onInterceptTouchEvent返回false,不拦截,那么事件将会传递给子view,子view在去调用自己的dispatch方法去纷发,这样事件就能被返回箭头接受,可以正常关闭activity
由于onInterceptTouchevent返回了false,所以事件执行完他里面的方法后就把事件传递给了子view,于是事件就从发源地activity 和linearlayout中的 dispatch 和 intercept 起作用,并没有onTouchEvent的事情了,具体细节看log输出描述,然后由于事件传递给了子view 所以 返回箭头生效,这个方法返回false和返回super产生的效果是一模一样的,这里就不在截图了有兴趣的可以输出一下
到此为止我们activity中只有一个viewgroup的场景基本分析完毕了,然后我们想liearlayout中添加一个textview如下图
因为我们这里加入的是最小单位的view就是view不能再添加额外的内容,我们手指触摸屏幕事件传递过程,有activity 到 liearlayout 在到view 在返回 linearlayout ,返回activity 直到消失,具体过程如下;
再来一个场景,这次我们让childview中的dispatch 事件返回false,
笔者本来也是对这个传递有点模糊的,今天博客写到这里我都能猜到打印结果了,由于textviewdispatch返回了false ,所以事件执行完dispatch down后直接把事假返回给父view linearlayout的onTouchEvent,由于onTouchEvent设置了touchlistener 所以后执行,然后就是父view也返回了super,所以事件传递给activity的onTouchEvent 由于activity的onTouchEvent也返回了super.所以事件消失,最后在activity中执行 move 和 up
然后我们看下打印结果;
写到这里,理解的事件传递在脑海里的模糊场景已经有点透明了,还需要更多的实践,文中可能有理解不到位的也请大神批正,到此我理解的事件传递在viewgroup 和view中全部结束,也感谢群里nil的指点谢谢!
如果你看完还是对这个过程不是很理解,请自己模拟场景打印log,因为我感觉没有在比笔者更笨出身更贫寒的了,当你模拟看log有点想吐甚至能猜到不同的返回值会是什么样的传递场景,那么你对事件传递的过程相比之前你的理解肯定有恍然大悟的!谢谢….