android View和ViewGroup的事件分发过程

一.View

1. 点击按钮的事件分发过程

(1)button的dispatchTouchEvent

    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);  
    } 

(2)button的setOnTouchListener的onTouch

button.setOnTouchListener(new OnTouchListener() {  
    @Override  
    public boolean onTouch(View v, MotionEvent event) {  
        Log.d("TAG", "onTouch execute, action " + event.getAction());  
        return false;  
    }  
});

(3)button的onTouchEvent
2.执行onTouchEvent(event)的条件

以下三条 有一条不满足, 那么就执行onTouchEvent. 都满足, 那么不执行onTouchEvent
(1)mOnTouchListener不为null
(2)并且view是enable的状态
(3)mOnTouchListener.onTouch(this, event)返回true

3.另外

如果view是可点击, 或者可长按的, 那么, onTouchEvent一定会返回true, 

后面的MOVE,UP等一定会被执行;但如果是imageview, 它默认不可点击, 那么会返回false, 将此事件消费掉.

因为虽然在onTouch事件里返回了false,可点击view中, 系统还是会在onTouchEvent方法中帮你返回true。

就因为这个原因,才使得后续动作ACTION_UP可以得到执行。

二.ViewGroup

1.点击LinearLayout中的button的事件分发流程

(1)Linear的dispatchTouchEvent ACTION_DOWN

(2)Linear的onInterceptTouchEvent ACTION_DOWN

(3)Button的dispatchTouchEvent ACTION_DOWN

(4)Button的onTouchEvent ACTION_DOWN

可以看出,想在View上触发事件,最先捕捉到事件的是View所在的ViewGroup,然后才传到view本身.

2. 详细说明

(1)ViewGroup首先捕获到DOWN事件,如果代码中不做TOUCH事件拦截(

    1.当前不允许拦截,即disallowIntercept =true,
    2.当前允许拦截但是不拦截,即disallowIntercept =false,但是onInterceptTouchEvent(ev)返回false ;//拦截只需返回true

    3.onInterceptTouchEvent默认是不拦截的,即返回false;如果你需要拦截,只要return true就行了,这要该事件就不会往子View传递了,并且如果你在DOWN retrun true ,则DOWN,MOVE,UP子View都不会捕获事件;如果你在MOVE return true , 则子View在MOVE和UP都不会捕获事件。
原因很简单,当onInterceptTouchEvent(ev) return true的时候,会把mMotionTarget 置为null ;

    )

     则开始查找当前x,y是否在某个子View的区域内,如果在,则把事件分发给此view。

(2)ACTION_MOVE事件,   把ACTION_DOWN时赋值的mMotionTarget,付给target ; 直接return target.dispatchTouchEvent(ev);
     总体上ACTION_MOVE在检测完是否拦截以后,直接调用了子View.dispatchTouchEvent,事件分发下去;

(3)判断当前是否是ACTION_UP
    分别重置拦截标志位以及将DOWN赋值的mMotionTarget置为null,下一次DOWN还会再赋值的
    最后,修改坐标系统,然后调用target.dispatchTouchEvent(ev);

3.补充说明

其实ViewGroup也是View的子类,如果没有找到能够处理该事件的子View,或者干脆就没有子View;
那么,它作为一个View,就相当于View的事件转发了~~直接super.dispatchTouchEvent(ev);

1、如果ViewGroup找到了能够处理该事件的View,则直接交给子View处理,自己的onTouchEvent不会被触发;
2、可以通过复写onInterceptTouchEvent(ev)方法,拦截子View的事件(即return true),把事件交给自己处理,则会执行自己对应的onTouchEvent方法
3、子View可以通过调用getParent().requestDisallowInterceptTouchEvent(true); 阻止ViewGroup对其MOVE或者UP事件进行拦截;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值