View事件分发记录

      Android中View的事件分发是一个复杂的过程,看了很多大牛关于这方面的博客和文章,受益匪浅,特写此文章以记录放置忘记!尊重原创,转载请注明http://write.blog.csdn.net/postlist。

网上很多文章都是带大家看源码,我这里通俗易懂的写出,想看源码的自己可以去深入的研究一下。

首先我们看一个事件分发的简单流程,其中不做任何的拦截的操作,直接上代码:

Activity的布局activity_main

<com.example.vg.VG2 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"
    tools:context=".MainActivity" >

    <com.example.vg.V3
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="#00a0e9"
         />

</com.example.vg.VG2>


下面是两个自定义的控件:
public class V2 extends Button{

	public V2(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public V2(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public V2(Context context) {
		super(context);
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		int action = event.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			Log.i("log", "View:dispatchTouchEvent-down");
			break;
		case MotionEvent.ACTION_MOVE:
			Log.i("log", "View:dispatchTouchEvent-move");
			break;
		case MotionEvent.ACTION_UP:
			Log.i("log", "View:dispatchTouchEvent-up");
			break;
		default:
			break;
		}
		return super.dispatchTouchEvent(event);
		return true;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int action = event.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			Log.i("log", "View:onTouchEvent-down");
			break;
		case MotionEvent.ACTION_MOVE:
			Log.i("log", "View:onTouchEvent-move");
			break;
		case MotionEvent.ACTION_UP:
			Log.i("log", "View:onTouchEvent-up");
			break;
		default:
			break;
		}
		
		
		return super.onTouchEvent(event);
//		return true;
//		return false;
	}

输出结果(注意顺序):

ViewGroup:dispatchTouchEvent-down

ViewGroup:onInterceptTouchEvent-down

View:dispatchTouchEvent-down

View:onTouchEvent-down

ViewGroup:onTouchEvent-down

通过看了这个打印结果,有的人可能会说了,为什么你这个没有做拦截操作,输出的只有down,没有move和up,你问的好,看来你的领悟能力很强,听我慢慢将来,因为ViewGroup和View在onTouchEvent中都没有消费事件,所以后续的事件交给了Activity去处理,现在我在Activity中重写dispatchTouchEvent和onTouchEvent:

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) {
		int action = ev.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			Log.i("log", "activity:dispatchTouchEvent-down");
			break;
		case MotionEvent.ACTION_MOVE:
			Log.i("log", "activity:dispatchTouchEvent-move");
			break;
		case MotionEvent.ACTION_UP:
			Log.i("log", "activity:dispatchTouchEvent-up");
			break;
		default:
			break;
		}
		return super.dispatchTouchEvent(ev);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int action = event.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			Log.i("log", "onTouchEvent-down");
			break;
		case MotionEvent.ACTION_MOVE:
			Log.i("log", "onTouchEvent-move");
			break;
		case MotionEvent.ACTION_UP:
			Log.i("log", "onTouchEvent-up");
			break;
		default:
			break;
		}
		return super.onTouchEvent(event);
	}
}
打印结果:

activity:dispatchTouchEvent-down        //Activity开始分发dowm事件

ViewGroup:dispatchTouchEvent-down         //ViewGroup开始分发dowm事件

ViewGroup:onInterceptTouchEvent-down //ViewGroup不拦截,向下传递,交给子View的dispatchTouchEvent

View:dispatchTouchEvent-down //View开始分发dowm事件

View:onTouchEvent-down //View不消费事件,交给上一级处理的onTouchEvent处理
ViewGroup:onTouchEvent-down  //ViewGroup也不消费事件,也交给上一级(Activity)

onTouchEvent-down  //在Activity的onTouchEvent处理(最终交给Activity处理)

activity:dispatchTouchEvent-move //Activity开始分发move事件

onTouchEvent-move  //Activity消费move事件

activity:dispatchTouchEvent-up //Activity开始分发up事件

onTouchEvent-up  //Activity消费up事件


总结:

1)事件分发是自上而下,ViewGroup中有3个方法,而View中有2个,少了一个onInterceptTouchEvent方法,因为view是最低一级,它不需要传递事件给子View。

2)事件分发是从顶层的View一直往下分发到手指按下的最里面的View,如果这个View的onTouchEvent()返回false,即不消费Touch事件,这个Touch事件就会向上找父布局调用其父布局的onTouchEvent()处理,如果这个View返回true,表示消费了Touch事件,就不调用父布局的onTouchEvent();注意:onTouchEvent()返回false后将事件交给上级处理,后续的事件就不交给这个操蛋的家伙了,谁让给你脸不要脸,让你不接受(这个是重点,容易让人误解)

3)onInterceptTouchEvent的返回值决定是否拦截事件并将事件交给onTouchEvent处理。true:拦截事件后交给自己的onTouchEvent处理,false:向下传递不拦截。当ViewGroup要拦截事件的时候,那么后续的事件序列都将交给它处理,而不用再调用onInterceptTouchEvent()方法了,onInterceptTouchEvent该方法并不是每次事件都会调用的
如果在onInterceptTouchEvent返回true,onInterceptTouchEvent方法中将不会收到后续的任何事件,目标子控件中除了ACTION_CANCEL外也不会接收分发的后续事件,所有的后续事件将会被交付到你自己的onTouchEvent()方法中,如果你不明白的话,直接看我下面的几个小例子秒懂!


首先,Android中的事件分发是从上至下而执行的。ACTION_DOWN事件为一个事件序列的开始,中间有若干个ACTION_MOVE,最后以ACTION_UP结束。

在事件分发中需要我们重写的有3个方法:

        1)dispatchTouchEvent    

这个方法的作用我们是否向下分发事件,一般我们不会去重写这个方法

2)   onInterceptTouchEvent (默认不拦截):在dispatchTouchEvent中调用(自己去看源码)

这个方法的作用是拦截,此方法默认返回的是false,false的作用是不拦截,分发的事件将传递给子View;如果我们返回了true就代表拦截,同一个事件序列的其他所有事件都会交由这个View处理,此时不再调View(ViewGroup)的onIntercept()方法去询问是否要拦截了,那么拦截到的事件将会交给onTouchEvent处理(如果onTouchEvent向处理的话它就返回true去处理吧)同样子View的事件将被拦截,后续事件也不会接收到。

        3)onTouchEvent:它也dispatchTouchEvent中调用(自己去看源码)

此方法返回true表示对事件进行消费,不向上传递;如果返回false表示对事件不进行消费,那么后续事件将不会再交给它处理,消费事件是自下向上,如果子View不进行消费,将交给上一级的onTouchEvent处理,如果上一级也不处理,再交给上一级,加入没有View或ViewGroupView去处理,最后将交给Activity中的onTouchEvent处理。



几个例子让你秒懂一切奥秘:

代码就不写了,直接用上面的代码。

1)ViewGroup的onInterceptTouchEvent返回true拦截,onTouchEvent返回true消费事件


2)ViewGroup返回onInterceptTouchEvent返回false,和返回默认值的效果一样


3)ViewGroup的onInterceptTouchEvent返回true


4)View的onTouchEvent返回true


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值