美文网首页
android事件分发详解

android事件分发详解

作者: shoneworn | 来源:发表于2018-08-22 16:56 被阅读10次

    为了便于讲解,本文只采用了两层来讲,即:ViewGroup包含一个View 。这里有必要讲一下,事件分发是从最顶层的持有dispatchTouchEvent()方法的View或ViewGroup开始的。逐层向下分发。

    ViewGroup部分

    ViewGroup持有dispatchTouchEvent()方法,我们先看看源码,看看它是如何向下分发的。

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
      
            final boolean intercepted;
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || mFirstTouchTarget != null) {
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                if (!disallowIntercept) {
                    intercepted = onInterceptTouchEvent(ev);
                    ev.setAction(action); // restore action in case it was changed
                } else {
                    intercepted = false;
                }
            } else {
                // There are no touch targets and this action is not an initial down
                // so this view group continues to intercept touches.
                intercepted = true;
            }
    }
    

    通过简化后的源码,可以看到,调用了dispatchTouchEvent()方法后,方法体内有onInterceptTouchEvent方法。那么,如果用户自定义ViewGroup后,重写了dispatchTouchEvent方法,但是,返回值并不是调用的super.dispatchTouchEvent(), 而是直接返回true或者false,那么,onInterceptTouchEvent都将不会执行。所以,这里一定要搞清楚。并不是像网上有些文章写的,返回true,就是分发,返回false,就不分发了,事实上,分发动作是在ViewGroup的dispatchTouchEvent内完成的。所以,返回true和false都一样,都不会分发。而且,都不会执行onTouch和onClick 了。 具体为什么,还是看dispatchTouchEvent()剩下部分的源码:

     @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
          if (!canceled && !intercepted) {
           final int childrenCount = mChildrenCount;
                if (newTouchTarget == null && childrenCount != 0) {
                      
                   final View[] children = mChildren;
                    for (int i = childrenCount - 1; i >= 0; i--) {
    
                         if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                            
                        }
                      }
                }
            }
    
            // Dispatch to touch targets.
            if (mFirstTouchTarget == null) {
                // No touch targets so treat this as an ordinary view.
                handled = dispatchTransformedTouchEvent(ev, canceled, null,
                        TouchTarget.ALL_POINTER_IDS);
            }
    }
    

    简化后,可以看到,不管拦截不拦截,都执行了一个方法,那就是dispatchTransformedTouchEvent ,这个方法时干啥的? 待会讲。这里先讲下,不拦截,方法体力的for循环在干啥,通过阅读源码,我这里没贴出来,可以看到,是在找可以向下分发的view,找到后,调用了dispatchTransformedTouchEvent去分发。那拦截了怎么也调用了呢?因为上面讲过,ViewGroup是不具有onTouch和onTouchEvent方法的。那怎么办?子类没有,父类有呀,ViewGroup的父类是View,那就还是要分发到View上去处理。dispatchTransformedTouchEvent就是这个工具,将其分发过去的工具。所以,这里拦截后,只处理ViewGroup自己事件。不管子view的事件了。
    到这里,ViewGroup就讲完了。

    View部分

    View部分就简单多了,没有onInterceptTouchEvent , 而onTouch 和onTouchEvent又都在dispatchTouchEvent方法内,所以只许看这个方法就行了。

       public boolean dispatchTouchEvent(MotionEvent event) {
      
    
        if (onFilterTouchEventForSecurity(event)) {
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                result = true;
            }
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }
    
            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }
    
      
        return result;
    }
    

    看看源码,一下子就这么明了了。就是这么简单,和ViewGroup一样,你要是重写View的dispatchTouchEvent方法后返回值给改成true或false,就和onTouch及onTouchEvent 说拜拜了。这两兄弟被你屏蔽了。 再看看onTouch和onTouchEvent啥关系。源码中清晰的写了。如果onTouch方法返回值为true, 那么result=true,那么下面的一个if语句第一个条件就无法满足了,后面的onTouchEvent就不会执行,被扼杀了。而onTouchEvent不能执行,那么其方法体内的performClick方法就不会执行。perform不执行,onClickListener就不会有回调。onClick方法就不会执行了。

    相关文章

      网友评论

          本文标题:android事件分发详解

          本文链接:https://www.haomeiwen.com/subject/oujyiftx.html