自己动手写一个测试Android事件传递机制的demo

注意:事件的传递,第一步,自父控件传向子控件的事件传递路线,中间不会有onTouchEvent事件,一旦有onTouchEvent事件发生,进入第二步,开始走自子控件向父控件的事件消费路线


很久很久很久以前,我就开始尝试来理解安卓的事件传递机制,可是我却一直都是模模糊糊的理解,整套机制,我看过数十遍,可是面试的时候,我仍然答不好这个问题,因为每次我写demo想验证这套机制的时候得到的结果都不是我想要的,久而久之我开始怀疑人生了。


安卓事件分两类,touch事件和keydown事件,流程机制类似。

demo以touch事件为蓝本。

事件传递过程中的三个事件回调函数:

public boolean dispatchTouchEvent(MotionEvent ev)
// onInterceptTouchEvent函数只在viewgroup的子类中存在
public boolean onInterceptTouchEvent(MotionEvent ev) 
public boolean onTouchEvent(MotionEvent event)


public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		Log.v("mytag", "MainActivity" + ".dispatchTouchEvent:");
		return super.dispatchTouchEvent(ev);//我最常做的是将super.dispatchTouchEvent(ev)的值保持到变量中,然后方便打印,但其实这样是不对的,这样会<span style="white-space:pre">		</span>//导致,打印出很多super中的Log,因为这里执行的super中会去调用activity的布局代码。这就是我一直以来被误导的原因
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Log.v("mytag", "MainActivity" + ".onTouchEvent:");
		return super.onTouchEvent(event);
	}
}


1、touch事件发生

2、最先拿到该事件的是,Activity的dispatchTouchEvent方法;Activity中没有 onInterceptTouchEvent  方法,而且Activity中的dispatchTouchEvent  拿到事件之后是默认传递给该Activity上面的子控件的dispatchTouchEvent,如果所有的子控件都没有消费掉该touch事件才会最终返回到Activity的onTouchEvent中来处理。如果在dispatchTouchEvent中返回true,也并不会执行到onTouchEvent中,只是截断了向子控件传递。

3、Activity中的layout的dispatchTouchEvent拿到该touch事件之后,如果返回true则直接传给;尽量不要修改dispatchTouchEvent方法,因为该方法设计原则是实现事件的分发,事件的拦截操作应该在onInterceptTouchEvent或者ontouchEvent中来做。也就是说,

@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		return super.dispatchTouchEvent(ev);
	}
上面这段代码是必须要执行的,要不然事件的分发流程就被打断,不管返回什么事件都不会向下传递。(事实上,经本人亲测,dispatchTouchEvent的返回值并没有什么卵用,主要是其中执行的super.dispatchTouchEvent(ev)在起作用,不知道这样的理解有没有问题)


写到这里发现我的代码没有什么用,就不贴了,心得总结如下。

总结:

一、如果事件被拦截了,想要找到原因,那么就可以从Activity开始,1、检查每个dispatchTouchEvent里面是不是都有执行过super.dispatchTouchEvent(ev)这句代码,如果没有则需要加上。2、检查各个父容器控件的onInterceptTouchEvent 中是不是有返回true,如果有,则证明是被该容器拦截了。3、检查各个子控件中的onTouchEvent中是不是有返回true的地方,如果是,则证明是该子控件消费掉了该事件导致事件的传递断裂。

二、如果想要拦截事件,1、如果当前控件是继承自ViewGroup的容器类控件,则可以在onInterceptTouchEvent 中返回true,那么事件的处理就会被传递到当前控件的onTouchEvent中,想要向当前容器的父容器继续传递则在onTouchEvent中返回false,想要在当前容器中消费掉该事件则返回true,消费掉后不会向父容器传递。2、如果当前控件是继承自View的控件,则可以在onTouchEvent中消费事件,事件被消费了之后就不会向后传递了。

注意:事件拦截的事情,千万不要想在dispatchTouchEvent中来做,这样子是不对的,而且万一不是很懂整套机制会浪费很多脑细胞的。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值