android-----关于事件分发机制中几点困惑测试

        这几天以来对Android开发艺术探索中关于事件机制的总结有点不太明白,今天特地通过demo测试如下两个结论:
        1. 某个View一旦决定拦截,那么这一个事件序列都只能由他来处理(如果事件序列能够传递给他的话),并且他的onInterceptTouchEvent不会再被调用;

        2. 某个View一旦开始执行处理事件,如果他不消费ACTION_DOWN事件(onTouchEvent返回false),那么同一事件序列中的其他事件都不再会交给他来处理,并且事件将重新交给他的父元素去处理;

        测试用例代码下载!!!!

      这里采用的测试布局文件是:

<com.hzw.eventtest.MyRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <com.hzw.eventtest.MyLinearLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent">
         <com.hzw.eventtest.MyButton
        	android:id="@+id/mybutton"
        	android:layout_width="wrap_content"
        	android:layout_height="wrap_content"
        	android:text="我的按钮" />
    </com.hzw.eventtest.MyLinearLayout>
</com.hzw.eventtest.MyRelativeLayout>

        也即测试布局图是:

                                               android-----关于事件分发机制中几点困惑测试_第1张图片

        测试1:

        对测试代码不做任何修改,Logcat输出:

 

                                                                                                     图1

        点击屏幕按钮会首先由MainActivity的dispatchTouchEvent进行分发,因为Activity没有拦截功能,接着由MyRelativeLayout的dispatchTouchEvent进行分发,同时调用它的onInterceptTouchEvent判断是否需要拦截,我们这里不拦截,则调用MyLinearLayout的dispatchTouchEvent进行分发,同时调用他的onInterceptTouchEvent判断是否需要拦截,这里也没进行拦截,那么就该MyButton进行分发了,因为他已经是View了,所以调用它的dispatchTouchEvent分发默认情况下onTouch方法返回false的话就执行onTouchEvent了,View的onTouchEvent默认返回值是true,因为我们上面所有方法的返回值都是super.的方式,所以事件到View的时候就被消费了;

        测试2:

        如果只修改MyLinearLayout$onInterceptTouchEvent如下:

@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			System.out.println("MyLinearLayout--->onInterceptTouchEvent--->ACTION_DOWN");
			return true;
		case MotionEvent.ACTION_MOVE:
			System.out.println("MyLinearLayout--->onInterceptTouchEvent--->ACTION_MOVE");
			break;
		case MotionEvent.ACTION_UP:
			System.out.println("MyLinearLayout--->onInterceptTouchEvent--->ACTION_UP");
			break; 
		default:
			break;
		}
		return super.onInterceptTouchEvent(ev);
	}
        也就是说只在MyLinearLayout中拦截DOWN事件;

        查看Logcat输出:

             

                                                                                               图2

        可以看到事件分发到第5行时,因为MyLinearLayout对DOWN事件进行了拦截,因而会执行他的onTouchEvent方法,又因为我们没有在onTouchEvent中对DOWN事件进行消费,所以传给上级MyRelativeLayout的onTouchEvent来进行处理,上级也没有对DOWN事件进行消费,那么他仍然会传给上级MainActivity的onTouchEvent来处理了,这个事件在这里得到了消费,那么接下来的MOVE和UP事件根据结论2就知道,MyRelativeLayout和MyLinearLayout是没有资格进行处理的,因为他们都没消费DOWN事件,因而都是由MainActivity的onTouchEvent来处理了;

        如果只修改MyLinearLayout$onTouchEvent会发生什么呢?

        @Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			System.out.println("MyLinearLayout--->onTouchEvent--->ACTION_DOWN");
			return true;
		case MotionEvent.ACTION_MOVE:
			System.out.println("MyLinearLayout--->onTouchEvent--->ACTION_MOVE");
                        break;
		case MotionEvent.ACTION_UP:
			System.out.println("MyLinearLayout--->onTouchEvent--->ACTION_UP");
			break; 
		default:
			break;
		}
		return super.onTouchEvent(event);
	}
        只在MyLinearLayout中消费了他的DOWN事件;

        查看Logcat输出:

               android-----关于事件分发机制中几点困惑测试_第2张图片

                                                                                                    图3

        可以发现如果只消费事件而不拦截相对应事件的话,对整个分发过程是没什么影响的,因为最终事件是由最里层的View处理了,而且也没从View里面回传回来;

        如果我们同时修改MyLinearLayout$onInterceptTouchEvent以及MyLinearLayout$onTouchEvent里面的DOWN事件,让他们都返回true的话会出现什么情况呢?

        查看Logcat输出有:

                 android-----关于事件分发机制中几点困惑测试_第3张图片

                                                                                                    图4

        可以发现DOWN事件在传递到MyLinearLayout之后调用它的onTouchEvent事件并且将其消费,那么接下来的MOVE以及UP事件同样也要传递到MyLinearLayout,这点不同于图2,因为图2中只设置了MyLinearLayout的DOWN拦截事件,但是最终DOWN事件是由MainActivity来处理的,所以之后的MOVE以及UP事件就干脆不会向下分发了,因为即使分发下去他们也没有资格执行,索性直接由MainActivity来处理MOVE以及UP事件了,但是图3显然不一样,这里是MyLinearLayout消费的DOWN事件,那么接下来的MOVE以及UP事件显然也应该传给他让他判断自己是否要处理这两个事件,如果自己不处理的话,那么直接就由MainActivity来处理,注意这里直接是由MainActivity来处理的;

        可能你对直接就由MainActivity来处理不太相信,我们可以在MyRelativeLayout的onTouchEvent中消费MOVE事件,假如你是正确的,那么事件在回传的过程中将会经过MyRelativeLayout的onTouchEvent方法,因为我们的布局是MainActivity--->MyRelativeLayout--->MyLinearLayout的,这时候如果你的观点是正确的话,那么会在MyRelativeLayout的onTouchEvent中消费了MOVE:

        查看Logcat输出:

              android-----关于事件分发机制中几点困惑测试_第4张图片

        注意红框部分,你会发现仍然还是直接调用的MainActivity的onTouchEvent方法,这一点也就告诉我们是谁消费的DOWN事件,谁才有资格处理接下来的MOVE和UP事件,如果最后事件还是没有处理的话,那么只能由Activity来处理了;

        测试3:

        我们现在设置MyRelativeLayout来拦截MOVE事件,MyLinearLayout来拦截并且消费DOWN事件:

        也就是我们需要修改MyRelativeLayout$onInterceptTouchEvent,以及MyLinearLayout$onInterceptTouchEvent以及MyLinearLayout$onTouchEvent;

        MyRelativeLayout$onInterceptTouchEvent

@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			System.out.println("MyRelativeLayout--->onInterceptTouchEvent--->ACTION_DOWN");
			break;
		case MotionEvent.ACTION_MOVE:
			System.out.println("MyRelativeLayout--->onInterceptTouchEvent--->ACTION_MOVE");
			return true;
		case MotionEvent.ACTION_UP:
			System.out.println("MyRelativeLayout--->onInterceptTouchEvent--->ACTION_UP");
			break; 
		default:
			break;
		}
		return super.onInterceptTouchEvent(ev);
	}
         MyLinearLayout$ onInterceptTouchEvent
@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			System.out.println("MyLinearLayout--->onInterceptTouchEvent--->ACTION_DOWN");
			return true;
		case MotionEvent.ACTION_MOVE:
			System.out.println("MyLinearLayout--->onInterceptTouchEvent--->ACTION_MOVE");
			break;
		case MotionEvent.ACTION_UP:
			System.out.println("MyLinearLayout--->onInterceptTouchEvent--->ACTION_UP");
			break; 
		default:
			break;
		}
		return super.onInterceptTouchEvent(ev);
	}
         MyLinearLayout$ onTouchEvent

@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			System.out.println("MyLinearLayout--->onTouchEvent--->ACTION_DOWN");
			return true;
		case MotionEvent.ACTION_MOVE:
			System.out.println("MyLinearLayout--->onTouchEvent--->ACTION_MOVE");
            break;
		case MotionEvent.ACTION_UP:
			System.out.println("MyLinearLayout--->onTouchEvent--->ACTION_UP");
			break; 
		default:
			break;
		}
		return super.onTouchEvent(event);
	}
        来查看Logcat输出:

                   android-----关于事件分发机制中几点困惑测试_第5张图片
        注意红框部分。可以发现第一次虽然我们设置了MyRelativeLayout来消费掉MOVE事件,但是很明显第一次MOVE事件和这并没有关系,因为他是由MainActivity的onTouchEvent来进行处理的,但是接下来的第二次MOVE事件就会首先由MyRelativeLayout的onTouchEvent方法来查看是否要消费该MOVE事件了,不消费的话才会由MainActivity的onTouchEvent方法来执行,我们这里是不消费,那么他就会执行MainActivity的onTouchEvent方法了,同时后面的UP事件也不会向MyLinearLayout传递了,因为MyRelativeLayout已经决定拦截事件MOVE,那么MOVE之后的事件将都交给MyRelativeLayout来处理了(只要改事件能够到达MyRelativeLayout的话);



你可能感兴趣的:(android,androd事件分发机制,事件分发机制测试)