5. 事件分发涉及到的函数及相应的作用
方法 | 作用 |
---|---|
dispatchTouchEvent | 进行事件分发 |
onInterceptTouchEvent | 事件拦截 |
onTouchEvent | 事件消耗(就是交给当前View处理) |
- dispatchTouchEvent: 用来进行事件分发,若事件能够传递到当前
View
,则此方法一定会被调用。 - onInterceptTouchEvent: 在
dispatchTouchEvent
方法内被调用,用来判断是否拦截某个事件。若当前View
拦截了某个事件,则该方法不会再被调用,返回结果表示是否拦截当前事件,该方法只在ViewGroup
中存在。 - onTouchEvent: 用来处理点击事件,返回结果表示是否消耗当前事件,若不消耗,则在同一事件序列中,当前
View
无法再次接收到事件。
这三个方法可用以下伪代码表示
public boolean dispatchTouchEvent(MotionEvent ev){
boolean consume = false;
if(onInterceptTouchEvent(ev)){
consume = onTouchEvent(ev);
}else{
consume = child.dispatchTouchEvent(ev);
}
return consume;
}
对应的根ViewGroup
,当一个点击事件产生时,Activity
会传递给它,这时它的dispatchTouchEvent
就会被调用,若该ViewGroup
的onInterceptTouchEvent
返回true
,代表拦截该事件,但是否消耗该事件,还要看它的onTouchEvent
的返回值,如果不拦截,则代表将事件分发下去给子View
,接着子View
的dispatchTouchEvent
方法会被调用,如此反复直到事件被最终处理。
6. Activity的事件分发
当一个点击事件发生时,事件最先传到Activity
的dispatchTouchEvent()
进行事件分发。这里主要要弄明白Activity
是怎么将事件分发到ViewGroup
中的
6.1 Demo演示
我们先看一个案例
(1) 自定义一个MyViewGroup
,继承自ViewGroup
,重写dispatchTouchEvent()
方法
public class MyViewGroup extends ViewGroup{
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i(TAG, "dispatchTouchEvent: ");
//这里我们暂时先返回false
return false;
}
}
(2) 在Activity
的布局中,使用该布局作为最外层布局
<com.ld.eventdispatchdemo.activitydispatch.MyViewGroup xmlns:android=“http://schemas.android.com/apk/res/android”
xmlns:app=“http://schemas.android.com/apk/res-auto”
xmlns:tools=“http://schemas.android.com/tools”
android:layout_width=“match_parent”
android:layout_height=“match_parent”
android:id=“@+id/myViewGroup”
android:orientation=“vertical”
tools:context=“.activitydispatch.ActivityDispatchActivity”>
</com.ld.eventdispatchdemo.activitydispatch.MyViewGroup>
(3) 重写该Activity
的dispatchTouchEvent()
和onTouchEvent()
方法,打印log日志
public class Activity extends AppCompatActivity{
…
private static final String TAG = “Activit_activitydispatch”;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(ev.getAction()==MotionEvent.ACTION_DOWN){
Log.i(TAG, "dispatchTouchEvent: ");
}
//这里是仿照源码的格式写的
if(getWindow().superDispatchTouchEvent(ev)){
Log.i(TAG, “dispatchTouchEvent: 这里被调用”);
return true;
}
return onTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i(TAG, "onTouchEvent: ");
return super.onTouchEvent(event);
}
}
当MyViewGroup
的dispatchTouchEvent
返回false
时,打印的log日志为:
Activit_activitydispatch: dispatchTouchEvent:
MyViewGroup_activitydispatch: dispatchTouchEvent:
Activit_activitydispatch: onTouchEvent:
Activit_activitydispatch: onTouchEvent:
Activit_activitydispatch: onTouchEvent:
Activit_activitydispatch: onTouchEvent:
Activit_activitydispatch: onTouchEvent:
当MyViewGroup
的dispatchTouchEvent
返回true
时,打印的log日志为:
Activit_activitydispatch: dispatchTouchEvent:
MyViewGroup_activitydispatch: dispatchTouchEvent:
Activit_activitydispatch: dispatchTouchEvent: 这里被调用
MyViewGroup_activitydispatch: dispatchTouchEvent:
Activit_activitydispatch: dispatchTouchEvent: 这里被调用
MyViewGroup_activitydispatch: dispatchTouchEvent:
Activit_activitydispatch: dispatchTouchEvent: 这里被调用
MyViewGroup_activitydispatch: dispatchTouchEvent:
Activit_activitydispatch: dispatchTouchEvent: 这里被调用
仔细观察可以看到,当MyViewGroup的dispatchTouchEvent返回false时,Activity的onTouchEvent会被调用,返回true时,不会被调用,这是什么原因呢?
你可能会有疑问,我的Activity
的dispatchTouchEvent()
方法内为何要这样写呢?别急,看完下面的源码你就知道了。
6.2 源码解析
目的: