android菜鸟之路-事件分发机制总结(一)

View事件分发机制

首先感谢郭大侠和鸿大哥的无私奉献
想看源码分析的可以直接跳到最后,有给出他们的源码分析的链接

在Activity里有一个Button,给Button添加事件如下
		button.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				Log.e(TAG, "button+setOnClickListener000");
			}
		});

		button.setOnTouchListener(new OnTouchListener()  
		{  
			@Override  
			public boolean onTouch(View v, MotionEvent event)  
			{  
				int action = event.getAction();  
				
				switch (action)  
				{  
				case MotionEvent.ACTION_DOWN:  
					Log.e(TAG, "button+onTouch ACTION_DOWN");
					break;  
				case MotionEvent.ACTION_MOVE:  
					Log.e(TAG, "button+onTouch ACTION_MOVE");  
					break;  
				case MotionEvent.ACTION_UP:  
					Log.e(TAG, "button+onTouch ACTION_UP"); 
					break;  
				default:  
					break;  
				}  
				
				return false;  
			}  
		});

然后点击按钮并轻轻滑动,会打印出button+onTouch ACTION_DOWN,button+onTouch ACTION_MOVE,button+onTouch ACTION_UP,button+setOnClickListener000
(可见onTouch方法先于onClick方法执行)
如果把onTouch()方法的返回值改为true,则会打印出button+onTouch ACTION_DOWN,button+onTouch ACTION_MOVE,button+onTouch ACTION_UP
为什么会这样呢?
你可以理解为当onTouch()返回true,就是被onTouch把事件消费掉了,事件不向后传递,所以onClick方法就不会执行了。

深入一点点分析

首先需要知道一点,只要你触摸到了任何一个控件,就一定会调用该控件的dispatchTouchEvent方法。
其实当我们触摸Button时,就会调用View的dispatchTouchEvent方法(因为Button本身没有这个方法,所以会向上面的父类一直查找,直到View)
那么View的这个方法里究竟做了什么呢?看下源码
	public boolean dispatchTouchEvent(MotionEvent event) {  
	    if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&  
	            mOnTouchListener.onTouch(this, event)) {  
	        return true;  
	    }  
	    return onTouchEvent(event);  
	} 
首先看看第一个判断条件,mOnTouchListener
	public void setOnTouchListener(OnTouchListener l) {  
	    mOnTouchListener = l;  
	} 
可见只要给控件添加了OnTouch方法,mOnTouchListener就不为空,第二判断条件-控件是否是enable的,按钮默认都是enable的,所以这里是true,最后会调用onTouch方法,假如返回了true,那么onTouchEvent方法就不会执行了,返回false,onTouchEvent方法才会会执行,根据之前的测试,可知onclick方法应该是在onTouchEvent里执行的了。

再来一小段截取的源码
	public boolean onTouchEvent(MotionEvent event) {  
		...
		if (((viewFlags & CLICKABLE) == CLICKABLE ||  
		(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {  
			switch (event.getAction()) {  
			case MotionEvent.ACTION_UP:  
				... 
				if (!post(mPerformClick)) {  
					performClick();  
				}  
			}  

			...
			return true;  
		} 
		return false;
	} 

1.当手指抬起时,会执行到performClick()方法,而onClick方法就在里面执行,这里不再进入源码。所以之前onTouch方法里返回true,这个onTouchEvent方法没有执行,所以performClick()方法没有执行,so  ~onClick方法没有执行。
2.只要(((viewFlags & CLICKABLE) == CLICKABLE ||  (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE))  为true,最后onTouchEvent就会返回true(不论action此时为ACTION_DOWN,ACTION_MOVE还是ACTION_UP),否则返回false。

切记,只有每个ACTION_DOWN,ACTION_MOVE,ACTION_UP事件对应的dispatchTouchEvent方法都返回true,才能依次往后执行,就是说如果dispatchTouchEvent方法里此时的event.getAction()==ACTION_DOWN,  你返回了false,那么后面的dispatchTouchEvent方法都不会执行(说白了,每个动作事件都会执行一次dispatchTouchEvent,执行ACTION_DOWN的时候返回了false,后面一系列其它的action就不会再得到执行了,也就是ACTION_MOVE,ACTION_UP事件将不会得到执行。这个先记着,要结合后面的ViewGroup的事件分发机制一起理解)。


想要深入理解的可以看看这两位大神的源码分析

郭霖大侠

鸿洋大哥


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值