android 事件分发机制(View)

来源:互联网 发布:攻壳机动队95知乎 编辑:程序博客网 时间:2024/06/05 18:59

    相信很多人在开发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();
                                }


现在来看看  performClick 的源码  

看到了 他在里面执行了onclick

回调到了用户界面      至此 简单的 事件分发已经完毕

0 0