再次深入研究Android事件分发机制,学习笔记。

之前研究过,但是有很多地方有不足,这次进行了相对透彻的研究,再次记录一下关于Android事件是如何分发的。

我用gimp画了一副图,先上图:

上面描述的场景是这样的:

A.MainActivity中有两个ViewGroup(Out_layout_0,Out_layout_1),为了更加全面的分析,我让这两个ViewGroup有重叠的部分,其中按照Z-Order的布局方式的话,

Out_layout_0要在Out_layout_1上面,也就是说Out_layout_0要先于Out_layout_1接收到Touch事件;

B.在Out_layout_0中还包含一个子ViewGroup(Inner_layout)。

场景描述完毕,开始说一下这个东西是怎么工作的:

1.首先说一下事件产生的顺序:一种:ACTION_DOWN=>ACTION_MOVE=>ACTION_UP;另一种:ACTION_DOWN=>ACTION_UP,快速点击的时候,没有产生MOVE

事件。

2.一旦事件在某层被拦截(onInterceptTouchEvent返回true)或者在某层被消费(onTouchEvent()返回true),那么后面产生的事件都会一层一层经过每层的

dispatchTouchEvent和onInterceptTouchEvent(),最终在进入该层的onTouchEvent()中进行处理(看上图);(红字表示同一层)

你可以在用条件判断语句,来根据具体事件决定是不是要拦截该事件或者消费该事件,比如消费MOVE事件:

	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		Log.e(TAG, "Layout_out_0+onTouchEvent:" + Common.getAction(ev));
                if(ev.getAction()==MotionEvent.ACTION_MOVE){
                         return true; 
                }
		return false;
	}


3.具体事件在拐弯的时候表现的行为不一样:

ACTION_DOWN是第一个事件,前面没有事件了,如过被拦截,那么他会在进入该层的onTouchEvent()中,如果不消费即在该层返回的是false,那么会进入

上层也就是父VIewGroup的onTouchEvent()中,一层一层,如果一直没有处理,最终经过MainActivity的onTouchEvent(),在这可以认为被MainActivity的onTouchEvent

消费;

ACTIOM_MOVE:参照ACTION_DOWN会在企图进入ACTION_DOWN拐弯的位置的onTouchEvent中,如果不被消费,即在该层onTouchEvent()返回的是false,那么直

接进入到最外层的MainActivity中的onTouchEvent(),而不会经过上面的没一层,这是与ACTION_DOWN不一样的地方,注意我为什么用了一个企图呢?因为中间可能被

onInterceptTouchEvent()发生拐弯,那么此时在ACTION_DOWN被消费的一层收不到ACTION_MOVE事件,此时ev.getAciton()返回的是none,这次ACTION_MOVE事件消失了,也不会继续往上层onTouch提交。而接下来的ACTION_MOVE事件不再经过该层的onInterceptTouchEvent()(还是会经过上层的onInterceptTouchEvent());

ACTION_UP:的行为跟ACTION_MOVE类似,不过ACTION_UP的参照:如果产生的事件是ACTION_DOWN=>ACTION_MOVE=>ACTION_UP那么参照ACTION_MOVE;

如果产生的事件是:ACTION_DOWN=>ACTION_UP那么参照的是ACTION_DOWN。剩下的行为就跟ACTION_MOVE参照ACTION_DOWN产生的行为是一样的了。


相信到这大家已经能为所欲为的截取各种事件了。

还有一种情况,就是跟上述描述的一样,MainActivity的孩子有两个,即Out_layout_0和Out_layout_1这个时候怎么办呢?

如果看过dispatchTouchEvent()的源码的化,可以在源码中有一个for循环,遍历每个child的dispatchTouchEvent(),根据Z-Order的顺序调用,即Out_layout_0优先,而

child.dispatchTouchEvent()是一个递归调用的过程,所以呢,会先遍历Out_layout_0的每一个子树,完毕之后才会除了里Out_layout_0,当然,一旦其中有在Out_layout_0

中有符合上面我描述的三条,中间有事件被消费或者拦截,那么就不会经过Out_layout_1了。


在就是还有一个细节问题,在onTouchEvent中,根据源码分析的化,如果该控件是CLICKABLE或者LONGCLICKABLE(可以通过setListener来设置控件是不是

因为在setClickListener或者setLongClickListener的源码中会把该控件的属性强制设置成为CLICKABLE或者LONGCLICKABLE),那么onTouchEvent会返回true,else

返回false,也就是说控件是CLICKABLE或者LONGCLICKABLE总是会消费事件的。


还有就是onTouchEvent的源码对事件的处理,CLICK实在ACTION_UP中处理的,LONGCLICK是在ACTION_MOVE中处理的,而且如果要执行CLICK,前提条件是

没有LONGCLICK,也就是说,如果一个控件即是LONGCLICK又是CLICK,那么要执行CLICK要在onLongClick()返回false。


好了学习笔记先到这了。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值