View和ViewGroup的事件分发总结

View事件分发:

当为一个Button设置OnClickListener事件后,单击该Button,首先会调用View的dispatchTouchEvent()方法进行事件分发,Button是View的子类,故调用View的该方法,

当mOnTouchListener!=null,并且该view为enable激活状态的时候,以及onTouch()方法返回true的时候才会调用onTouchEvent()方法。我们在为View设置OnTouchListener的时候默认为mOnTouchListener赋值,并且Button默认为enable状态,所以当onTouch()返回false的时候,dispatchTouchEvent()方法直接返回true,不再响应事件.

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

如果为该Button也设置了OnClickListener,首先会执行onTouch()方法再执行onClick()方法,从上面可以得出onClick()方法与onTouchEvent(event)方法有关.

当event.getAction()==ACTION_UP时,会首先判断是否是OnLongClickListener(500ms后),否则执行performClick(),也就是onClick().

如果我们也设置了OnLongClickListener,那么会先执行onLongClick()方法,当返回值为false时(默认false),会继续执行onClick方法,否则不再继续执行.

public boolean onTouchEvent(MotionEvent event) {  
        final int viewFlags = mViewFlags;  
  
        if ((viewFlags & ENABLED_MASK) == DISABLED) {          
            return (((viewFlags & CLICKABLE) == CLICKABLE ||  
                    (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));  
        }   
        if (mTouchDelegate != null) {  
            if (mTouchDelegate.onTouchEvent(event)) {  
                return true;  
            }  
        }  
  
        if (((viewFlags & CLICKABLE) == CLICKABLE ||  
                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {  
            switch (event.getAction()) {  
                case MotionEvent.ACTION_UP:  
                    boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;  
                    if ((mPrivateFlags & PRESSED) != 0 || prepressed) {                      
                        if (!mHasPerformedLongPress) {  
                            removeLongPressCallback();                           
                            if (!focusTaken) {                               
                                if (mPerformClick == null) {  
                                    mPerformClick = new PerformClick();  
                                }  
                                if (!post(mPerformClick)) {  
                                    performClick();  
                                }  
                            }  
                        }                          
                    }  
                    break;  
  
                case MotionEvent.ACTION_DOWN:  
                    if (mPendingCheckForTap == null) {  
                        mPendingCheckForTap = new CheckForTap();  
                    }  
                    mPrivateFlags |= PREPRESSED;  
                    mHasPerformedLongPress = false;  
                    postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());  
                    break;  
  
                case MotionEvent.ACTION_CANCEL:  
                    mPrivateFlags &= ~PRESSED;  
                    refreshDrawableState();  
                    removeTapCallback();  
                    break;  
  
                case MotionEvent.ACTION_MOVE:  
                   
                    break;  
            }  
            return true;  
        }  
  
        return false;  
    }  


注意:一般情况下,onTouchEvent()都是返回true的,也是就当onTouchEvent()被调用的时候dispatchTouchEvent()的返回值一样,当onTouchEvent()返回true,剩下的action才能得以执行.


ViewGroup事件分发:

其实Android事件分发是先传递到ViewGroup,再由ViewGroup传递到View的。,当一个ViewGroup中的一个子View发出onTouch事件的时候,首先由父类的dispatchTouchEvent()进行事件分发,再调用onInterceptTouchEvent方法对事件进行拦截(默认返回false),返回true则对事件进行拦截,不再对子View进行事件分发.

如果子View消费掉事件后,ViewGroup中将接收不到任何事件。

public boolean onInterceptTouchEvent(MotionEvent ev) {  
    return false;  
} 
public boolean dispatchTouchEvent(MotionEvent ev) {  
    final int action = ev.getAction();  
    final float xf = ev.getX();  
    final float yf = ev.getY();  
    final float scrolledXFloat = xf + mScrollX;  
    final float scrolledYFloat = yf + mScrollY;  
    final Rect frame = mTempRect;  
    boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;  
    if (action == MotionEvent.ACTION_DOWN) {  
        if (mMotionTarget != null) {  
            mMotionTarget = null;  
        }  
        if (disallowIntercept || !onInterceptTouchEvent(ev)) {  
            ev.setAction(MotionEvent.ACTION_DOWN);  
            final int scrolledXInt = (int) scrolledXFloat;  
            final int scrolledYInt = (int) scrolledYFloat;  
            final View[] children = mChildren;  
            final int count = mChildrenCount;  
            for (int i = count - 1; i >= 0; i--) {  
                final View child = children[i];  
                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE  
                        || child.getAnimation() != null) {  
                    child.getHitRect(frame);  
                    if (frame.contains(scrolledXInt, scrolledYInt)) {  
                        final float xc = scrolledXFloat - child.mLeft;  
                        final float yc = scrolledYFloat - child.mTop;  
                        ev.setLocation(xc, yc);  
                        child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;  
                        if (child.dispatchTouchEvent(ev))  {  
                            mMotionTarget = child;  
                            return true;  
                        }  
                    }  
                }  
            }  
        }  
    }  

disallowIntercept 这个参数指是否禁用掉拦截功能,默认为false,子view可以通过调用getParent().requestDisallowInterceptTouchEvent(true)阻止ViewGroup对其MOVE或者UP事件进行拦截;同样ViewGroup也可以通过该属性返回true,拦截子View的事件,自己进行处理。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值