- Touch 事件的传递方式以及相关方法
Touch事件相关方法 |
功能 |
Activity |
ViewGroup |
View |
public boolean dispatchTouchEvent(MotionEvent ev) |
事件分发 |
Yes |
Yes |
Yes |
public boolean onInterceptTouchEvent(MotionEvent ev) |
事件拦截 |
No |
Yes |
No |
public boolean onTouchEvent(MotionEvent ev) |
事件响应 |
Yes |
Yes |
Yes |
Android中调用这个方法,用来传递和分发触摸事件,此方法返回值为布尔类型的值,通过返回true或false,来决定触摸事件是否向下传递。此外可以在子类重写dispatchTouchEvent方法,通过返回true或false来控制事件的分发和消费。(着重关注View和ViewGroup的事件分发的功能,下同)View 中事件的分发和ViewGroup事件的分发是有区别的,也就是两个类中的dispatchTouchEvent方法内容不一样。如果对此不太了解的可以参考郭霖大神的两边博客 Android事件分发机制完全解析,带你从源码的角度彻底理解(上)和Android事件分发机制完全解析,带你从源码的角度彻底理解(下),这两篇博客对view事件分发和viewGroup事件分发介绍的非常详细。
通过返回true或false,来判断在触摸事件传递过程中,是否拦截某个事件。从上表中可以看到,只有ViewGroup具有事件拦截的功能,ViewGroup源码中
onInterceptTouchEvent(MotionEvent ev)方法默认返回false,表示对所有的事件都不拦截。不过可以在ViewGroup的子类当中重写此方法,通过返回ture或false来判断触摸事件的拦截与否。- Touch事件
- Down:一次触摸事件的第一个MotionEvent对象,即手指初次接触屏幕。
- Up:通常为一次触摸事件的最后一个MotionEvent对象,即手指离开屏幕。
- Move:通常多次发生在一次触摸事件之中。表示触摸点发生了移动,我们通常把手指放到屏幕上,实际也会触发该事件,因为人手总是在轻微抖动的。
- Cancel:常用于取消某个触摸事件,一般是由程序逻辑来指定该事件,用于取消某次触摸事件。
- OutSide:当触摸点发生在响应事件的View之外时,传递的事件,通常由程序逻辑来指定。
- Touch 案例
- 情况1
|
dispatchTouchEvent |
onInterceptTouchEvent |
onTouchEvent |
FatherLayout |
return super.dispatchTouchEvent(ev); |
return super.onInterceptTouchEvent(ev); |
return
super.onTouchEvent(event);
|
ChildLayout |
return super.dispatchTouchEvent(ev); |
return super.onInterceptTouchEvent(ev); |
return
super.onTouchEvent(event);
|
ChildButtonView |
return super.dispatchTouchEvent(ev); |
无
|
return
super.onTouchEvent(event);
|
连同连同Log日志用一张图来说明上述ACTION_DOWN触摸事件分发流程,如下:
情况1小结:
- 从Log日志可以看出,Touch事件先处理ACTION_DOWN事件,用于定位目标View,之后的move和up事件,都会在此view中处理。
- dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent都是调用父类方法得到的返回值,其中super.onInterceptTouchEvent(ev)默认返回false即不会拦截触摸事件。
- 因为 ChildButtonView继承自Button,重写的onTouchEvent方法中调用super.onTouchEvent(event)方法,默认接收并消费ACTION_DOWN事件,并返回true。即定位此View为目标View,后续的Move和Up事件,也会传到这里进行事件的处理。
- 情况2
dispatchTouchEvent
onInterceptTouchEvent
onTouchEvent
FatherLayout
return super.dispatchTouchEvent(ev);
return super.onInterceptTouchEvent(ev);
return super.onTouchEvent(event);
ChildLayout
return super.dispatchTouchEvent(ev);
return super.onInterceptTouchEvent(ev);
return super.onTouchEvent(event);
ChildButtonView
return super.dispatchTouchEvent(ev);
无return false
- 从Log日志可以看出,Touch事件仍旧是先处理ACTION_DOWN事件。
- ChildButtonView 重写的onTouchEvent方法中返回值为false,表示ChildButtonView 不会处理并消费该ACTION_DOWN事件
- 因为FatherLayout、ChildLayout重写的onTouchEvent方法中调用super.onTouchEvent(event)方法,因为相对布局默认不会消费ACTION_DOWN事件,所以会返回一个false,ACTION_DOWN事件此时会如紫色的箭头那样标示的一样继续向上传递,一直传到Activity中的OntouchEvent方法中。
- 情况3
-
dispatchTouchEvent
onInterceptTouchEvent
onTouchEvent
FatherLayout
return
super.dispatchTouchEvent(ev);
return
super.onInterceptTouchEvent(ev);
return true;
ChildLayout
return
super.dispatchTouchEvent(ev);
return
super.onInterceptTouchEvent(ev);
return super.onTouchEvent(event);
ChildButtonView
return
super.dispatchTouchEvent(ev);
无return false
-
- FatherLyout中OntouchEvent方法中,让其返回ture,表示有FatherLayout接收并消费ACTION_DOWN事件。后续的Move和up事件也会在此View中处理。
- 情况4
|
dispatchTouchEvent |
onInterceptTouchEvent |
onTouchEvent |
FatherLayout |
return super.dispatchTouchEvent(ev); |
return super.onInterceptTouchEvent(ev); |
return true; |
ChildLayout |
return super.dispatchTouchEvent(ev); |
return super.onInterceptTouchEvent(ev); |
return true; |
ChildButtonView |
return super.dispatchTouchEvent(ev); |
无
|
return false |
- 情况5(主要讨论OnInterceptTouchEvent方法中的返回值,此时不在讨论onTouchEvent方法中的返回值)
|
dispatchTouchEvent |
onInterceptTouchEvent |
onTouchEvent |
FatherLayout |
return super.dispatchTouchEvent(ev); |
return super.onInterceptTouchEvent(ev); |
return true; |
ChildLayout |
return super.dispatchTouchEvent(ev); |
return true; |
return true; |
ChildButtonView |
return super.dispatchTouchEvent(ev); |
无
|
return false |
- ChildLayout中重写的OnInteceptTouchEvent方法,返回值为true,表示会将该ACTION_DOWN拦截,不在向下进行传递,并且会将该ACTION_DOWN事件,交由自己调用onTouchEvent方法进行判断处理。
- 如果将FatherLayout中的OnInterceptTouchEvent方法返回值改为true,与情况5类似,不在进行详细分析。
- 情况6(主要讨论dispatchTouchEvent方法中的返回值,此时不在讨论onInterceptTouchEvent和onTouchEvent方法中的返回值)
|
dispatchTouchEvent |
onInterceptTouchEvent |
onTouchEvent |
FatherLayout |
return super.dispatchTouchEvent(ev); |
return super.onInterceptTouchEvent(ev); |
return true; |
ChildLayout |
return super.dispatchTouchEvent(ev);
|
return super.onInterceptTouchEvent(ev); |
return true; |
ChildButtonView |
return ture; |
无
|
return false |
- 如果在ChildButtonView重写的dispatchTouchEvent方法中,直接返回false,那么不会调用onTouchEvent方法。同样的在FatherLayout和ChildLayout中既不会调用onTouchEvent方法,也不会调用onInterceptTouchEvent方法。