对于ViewGroup
来讲,与事件分发相关的方法包括:android
public boolean dispatchTouchEvent(MotionEvent event)
public boolean onInterceptTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event)
复制代码
对于View
来讲,与事件分发相关的方法包括:bash
public boolean dispatchTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event)
复制代码
Down
分发的理解对于Down
分发的过程,网上看了不少的例子和图,可是都没能好好理解,最后仍是本身总结了一种方案,这个方案的核心就是染色:函数
View
树上每一个节点都是白色的。dispatchTouchEvent
时,在返回以前都会有一个返回值,若是这个返回值为真,那么它本身就会变成红色。dispatchTouchEvent
时,它既是在尝试给子节点进行染色,也是在尝试给本身着色,当某个子节点的dispatchTouchEvent
方法返回时,取该子节点的颜色对本身进行着色;若是遍历完它全部的子节点,它仍然没有变成红色,那么调用它本身的onTouchEvent
,若是返回true
,那么把本身染成红色。ViewGroup/View
来讲,有可能染色成功只包括两种途径:子节点的dispatchTouchEvent
返回时,取子节点的颜色对本身着色;经过本身的onTouchEvent
方法来着色。而且,只有前一种途径不成功时才会用后一种途径。dispatchTouchEvent
来染色或者经过本身的onTouch
来染色,它会直接返回。从伪代码来看:ui
public Color color = white;
public boolean dispatchTouchEvent(MotionEvent event) {
int childCount = getChildCount;
for (i = childCount - 1; i >= 0; i--) {
View child = getChildAt(i);
boolean result = child.dispatchTouchEvent(event);
if (result) {
color = RED;
return true;
}
}
boolean touchRes = onTouchEvent(event);
if (touchRes) {
color = RED;
}
return touchRes;
}
复制代码
在Down
事件分发完后,咱们能够发现这么个现象。spa
Down
分发的特色对于一个没有重写以上关键方法而且位于View
树上的ViewGroup/View
来讲,它Down
事件的分发具备如下几个特色:code
dispatchTouchEvent
dispatchTouchEvent
是否被回调,由它的父容器决定的。dispatchTouchEvent
被调用时,它会先逆序依次调用下一级子节点的dispatchTouchEvent
方法。dispatchTouchEvent
返回了true
,那么不会继续调用剩余未遍历子节点的dispatchTouchEvent
,而且它自身的onTouchEvent
不会被回调。onInterceptTouchEvent
只有ViewGroup
才有,它是否被回调取决于dispatchTouchEvent
是否被回调。xml
onTouchEvent
onTouchEvent
是由本身回调的,是否被回调,必须同时知足如下两个条件:事件
dispatchTouchEvent
被回调。View
树的叶节点dispatchTouchEvent
都返回false
。Move/Up
分发在Move/Up
事件分发的时候,其实就是根据以前着色的结果来往下传递事件,它的传递只须要遵循下面的原则:只会分发给红色的节点,遇到白色的节点就中止往下分发。ip
咱们举一个简单的例子: utf-8
ViewGroup1
返回true
。Root
调用ViewGroup1
的dispatchTouchEvent
,而ViewGroup1
此时是白色,所以它继续调用它的子节点,也就是View21
的dispatchTouchEvent
,可是View21
没有子节点,所以它调用本身的onTouchEvent
,它的dispatchTouchEvent
方法返回,而此时,ViewGroup2
全部的子节点都遍历完了,它依然没有变成红色,所以它调用本身的onTouchEvent
,因为该方法返回false
,所以它也返回了,而且在返回时依然是白色。接下来Root
取ViewGroup2
的颜色对本身着色,着色完成以后发现本身仍然是白色,那么它就继续调用有可能使本身染色成功的方法,ViewGroup1
的dispatchTouchEvent
,因为它的dispatchTouchEvent
返回true
,所以它会把本身染成红色,因为它已经变成红色了,那么它也没有权利对子节点进行染色,所以它的dispatchTouchEvent
返回,Root
收到返回值时,取ViewGroup1
的颜色对本身进行着色,结果它发现本身是红色了,那么Root
也不会调用任何可能对本身染色的方法,而是直接返回了。ROOT
和ViewGroup1
变为红色节点。只要理解了上面的思想,其实各类状况均可以对应到,下面的例子只是为了让你们可以证实本身的想法是否正确罢了,因此就不过多解释了:
<?xml version="1.0" encoding="utf-8"?>
<com.example.lizejun.repoviews.LogFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:tag="ViewGroup$Root"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.lizejun.repoviews.MainActivity">
<com.example.lizejun.repoviews.LogFrameLayout
android:tag="ViewGroup1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.lizejun.repoviews.LogTextView
android:tag="ViewGroup1$View1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.example.lizejun.repoviews.LogTextView
android:tag="ViewGroup1$View2"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.example.lizejun.repoviews.LogFrameLayout>
<com.example.lizejun.repoviews.LogFrameLayout
android:tag="ViewGroup2"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.lizejun.repoviews.LogTextView
android:tag="ViewGroup2$View"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</com.example.lizejun.repoviews.LogFrameLayout>
</com.example.lizejun.repoviews.LogFrameLayout>
复制代码
ViewGroup2
的dispatchTouchEvent
返回false
ViewGroup2
的dispatchTouchEvent
返回true
ViewGroup1
下的孩子节点View2
返回了false
ViewGroup1
下的孩子节点View2
返回了true
ViewGroup2
的onTouchEvent
返回了false
ViewGroup2
的onTouchEvent
返回了true
ViewGroup1
下的孩子节点View2
返回了false
ViewGroup1
下的孩子节点View2
返回了true