相信很多人在开发Android的时候 遇到不少问题 比如 手势的冲突 , 比如 为什么我触摸这个按钮无效了 等各种莫名其妙的问题。。。 其实在工作中 这方面用的挺多 自己也大概了解整个流程 但是一直没有细致的去分析里面的每个细节 具体实现 掌握Android事件分发机制是必不可少的,而Android事件分发机制绝对不是三言两语就能说得清的。 很多东西应该从浅到深 先探究View的事件分发,下篇再去探究难度更高的ViewGroup的事件分发。
比如一个很简单的单击事件
Button bt=new Button(this);
bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
我们就可以监听到用户手指点击按钮的事件了
比如
bt.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return false;
}
});
onTouch方法里能做的事情比onClick要多一些,比如判断手指按下、抬起、移动等事件。那么如果我两个事件都注册了 他会先执行什么呢? 实验下看看
很明显 他是先执行 onTouch 再去执行onClick 并且ontouch 执行了多次
这个到底是为什么呢? 直接来看源码 从回调函数=
直接点击进去 发现这个函数是在 view 里面调用的 setOnClickListener
发现找了半天没有找到 哪里调用 onClick 继续看另外一个 setOnTouchListener
看到了这里进行了事件的分发 首先你需要知道一点,只要你触摸到了任何一个控件,就一定会调用该控件的dispatchTouchEvent方法 当我们去触摸按钮的时候 他会先去执行dispatchTouchEvent 方法 可是你会发现Button类里并没有这个方法,那么就到它的父类TextView里去找一找,你会发现TextView里也没有这个方法,那没办法了,只好继续在TextView的父类View里找一找
其实这里的代码也比较简单 核心在于这里
if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
return true;
}
第一个条件 是: 当前事件是否被注册了
第二个条件是当前的控件是否可用
第三个条件就是 ontouch 返回是否为 true
这三个条件都为真,就返回true,否则就去执行onTouchEvent(event)方法并返回。
现在我们可以结合前面的例子来分析一下了,首先在dispatchTouchEvent中最先执行的就是onTouch方法,因此onTouch肯定是要优先于onClick执行的,也是印证了刚刚的打印结果。而如果在onTouch方法里返回了true,就会让dispatchTouchEvent方法直接返回true,不会再继续往下执行。而打印结果也证实了如果onTouch返回true,onClick就不会再执行了。
这个时候你会想 onclick 是不是在onTouchEvent 里面被执行的 ? 接下来看下 onTouchEvent 源码
在这里 谷歌对用户的手势做了大量的计算 大量的识别
在源码里看到 这一句 if (!post(mPerformClick)) { 如果用户按下 并且马上弹起的话 那就确定为 单击事件 就去执行了
performClick();
}
看到了 他在里面执行了onclick
回调到了用户界面 至此 简单的 事件分发已经完毕