码迷,mamicode.com
首页 > 移动开发 > 详细

Android:View事件分发机制

时间:2015-06-13 17:16:31      阅读:139      评论:0      收藏:0      [点我收藏+]

标签:android   view事件分发   

关于View事件分发机制的文章已经有很多了,推荐郭霖和鸿洋的两篇文章,
http://blog.csdn.net/guolin_blog/article/details/9097463
http://blog.csdn.net/lmj623565791/article/details/38960443
结合他们写的,自己简单总结一下,可能只适用个人。


流程

只要你触摸到了任何一个控件,就一定会调用该控件的dispatchTouchEvent方法,源码如下(最新的API源码已经不是这样了,但是分析依然可行)

public boolean dispatchTouchEvent(MotionEvent event) {  
    ```
    if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&  
            mOnTouchListener.onTouch(this, event)) {  
        return true;  
    }  
    return onTouchEvent(event);  
}  

从这个方法可以看出,当控件setOnTouchListener后整个事件分发的流程如下:
View.dispatchEvent -> OnTouchListener.onTouch -> View.onTouchEvent

其中dispatchTouchEvent是当我们对View执行动作,如按下、移动、抬起等动作,系统调用的;onTouch就是程序员写的事件监听器setOnTouchListener(new OnTouchListener(){...})

当我们在onTouch方法里面返回true时,这时dispatchTouchEvent方法就会返回true而不会把事件分发到onTouchEvent了,而onClick方法、onLongClick方法正是在onTouchEvent方法里面调用的,所以只有在onTouch方法里面返回了false,才有可能触发onClickonLongClick方法。

观察onTouchEvent方法的源码(为了不占篇幅,直接从上面的文章看)我们可以知道:
①如果一个View是enable和clickable的时候,这个onTouchEvent一定会返回true,这个结论有什么用呢,当dispatchTouchEvent在进行事件分发的时候,只有这个方法返回true,才会触发下一个动作的事件。所以当onTouch方法返回false,事件会分发到onTouchEvent,如果View是enable和clickable的,必然会返回true,这样其他动作的事件才能继续触发dispatchTouchEvent。假如我们自己写一个自定义控件去继承Button,重写dispatchTouchEvent方法,将这个方法返回false时。我们点击这个Button,事件在执行完按下这个操作后就被消费了,当你抬起手指时系统也不会调用再dispatchTouchEvent了!
②当处在MotionEvent.ACTION_UP时,如果系统判定之前处在MotionEvent.ACTION_DOWN执行过长按操作,即调用了下面这个performLongClick方法(其实内部就是回调OnLongClickListeneronLongClick方法),并且返回的是false,才能触发onClick。否则onLongClick方法返回truemHasPerformedLongPress就变为true,就无法执行
performClick方法了。

if (performLongClick()) {  
                    mHasPerformedLongPress = true;  
                }  
if (!mHasPerformedLongPress) {  
                            // This is a tap, so remove the longpress check  
                            removeLongPressCallback();  

                            // Only perform take click actions if we were in the pressed state  
                            if (!focusTaken) {  
                                // Use a Runnable and post this rather than calling  
                                // performClick directly. This lets other visual state  
                                // of the view update before click actions start.  
                                if (mPerformClick == null) {  
                                    mPerformClick = new PerformClick();  
                                }  
                                if (!post(mPerformClick)) {  
                                    performClick();  
                                }  
                            }  
                        }  

小结

当你操作一个控件时,不管是按下、移动、抬起,在事件中途未被消费的情况下系统会按照View.dispatchEvent -> OnTouchListener.onTouch -> View.onTouchEvent分发下去。

如,按下控件时产生一个MotionEvent.ACTION_DOWN事件,系统首先将事件分发到dispatchTouchEvent,然后将事件分发到程序员写的onTouch方法,

  1. 如果这个onTouch方法返回了truedispatchTouchEvent则返回true,事件不会传递到onTouchEvent
  2. 如果onTouch方法返回了falsedispatchTouchEvent将会调用onTouchEvent方法,在这个方法内处理各种逻辑。
    1. 当处理ACTION_DOWN时经过系统判断此次为长按操作,将回调程序员写的长按方法,如果程序员写的onLongClick方法返回true,将使得长按标志位为true
    2. 当处理ACTION_UP时如果长按标志位为false时,才会回调onClick方法,默认情况下长按标志位为false
  3. 如果dispatchTouchEvent方法返回false,则无法触发其他动作的事件,这里要分清事件是否会触发以及事件是否会分发。

执行完按下动作后执行抬起动作,系统产生MotionEvent.ACTION_UP事件,则又按上述事件分发流程走一遍。

Android:View事件分发机制

标签:android   view事件分发   

原文地址:http://blog.csdn.net/leelit/article/details/46482909

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!