简单的讨论下关于Android的事件分发,其实网上的介绍很多,但是每次看完我都记的很晕,而我也只想知道当不同的返回值事件走的流程,所以这也只为自己做个简单的记录
首先说一下关于事件分发ViewGroup和View对应的方法
ViewGroup:dispatchTouchEvent、onTouchEvent、onInterceptTouchEvent、
View:dispatchTouchEvent、onTouchEvent
再定义了两个类GroupTest继承于LinearLayout(ViewGroup)和ButtonTest继承于Buttom(View),界面布局:
<com.mmf.ibinderdemo.GroupTest
android:id="@+id/lyt_test"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.mmf.ibinderdemo.ButtonTest
android:id="@+id/btn_test"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="click"/>
</com.mmf.ibinderdemo.GroupTest>
一、事件拦截
onInterceptTouchEvent(MotionEvent ev)方法
从上面可以看出这个方法只有ViewGroup有,作用是拦截事件向下传递,啥意思呢,就是当你的ViewGroup中有子控件,而在onInterceptTouchEvent被拦截了,那么你的子控价就收不到touch事件,我们从代码中来看这个效果
在GroupTest复写事件分发的三个方法
@Override
public boolean onInterceptTouchEvent(MotionEvent ev){
super.onInterceptTouchEvent(ev);
Log.e("Touch = ", "group onInterceptTouchEvent "+ ev.getAction() );
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("Touch = ", "group onTouchEvent "+ event.getAction() );
return super.onTouchEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean dispatchTouch = super.dispatchTouchEvent(ev);
Log.e("Touch = ", "group dispatchTouchEvent + " +dispatchTouch +ev.getAction());
return dispatchTouch;
}
ButtonTest复写
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("Touch = ", "chile touch");
return super.onTouchEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.e("Touch = ", "chile dispatchTouchEvent");
return super.dispatchTouchEvent(event);
}
当onInterceptTouchEvent返回true时查看运行结果
10-20 05:17:13.207 8138-8138/com.mmf.ibinderdemo E/Touch =: group onInterceptTouchEvent 0
10-20 05:17:13.208 8138-8138/com.mmf.ibinderdemo E/Touch =: group onTouchEvent 0
10-20 05:17:13.208 8138-8138/com.mmf.ibinderdemo E/Touch =: group dispatchTouchEvent + true0
10-20 05:17:13.302 8138-8138/com.mmf.ibinderdemo E/Touch =: group onTouchEvent 1
10-20 05:17:13.302 8138-8138/com.mmf.ibinderdemo E/Touch =: group dispatchTouchEvent + true1
10-20 05:17:13.303 8138-8138/com.mmf.ibinderdemo E/MainActivity: lyt_test: grouptrue
当onInterceptTouchEvent返回false时查看运行结果
10-20 05:28:46.053 8362-8362/com.mmf.ibinderdemo E/Touch =: group onInterceptTouchEvent 0
10-20 05:28:46.053 8362-8362/com.mmf.ibinderdemo E/Touch =: chile dispatchTouchEvent
10-20 05:28:46.053 8362-8362/com.mmf.ibinderdemo E/Touch =: chile onTouchEvent
10-20 05:28:46.053 8362-8362/com.mmf.ibinderdemo E/Touch =: group dispatchTouchEvent + true0
10-20 05:28:46.183 8362-8362/com.mmf.ibinderdemo E/Touch =: group onInterceptTouchEvent 1
10-20 05:28:46.183 8362-8362/com.mmf.ibinderdemo E/Touch =: chile dispatchTouchEvent
10-20 05:28:46.183 8362-8362/com.mmf.ibinderdemo E/Touch =: chile onTouchEvent
10-20 05:28:46.183 8362-8362/com.mmf.ibinderdemo E/Touch =: group dispatchTouchEvent + true1
10-20 05:28:46.185 8362-8362/com.mmf.ibinderdemo E/MainActivity: btn_test: chiletrue
从以上结果可以看出当onInterceptTouchEvent返回true时会拦截事件的分发,子view接收不到事件,不执行onTouchEvent事件
如果返回 false,则表示不会拦截该事件,事件会被传递到子 View 上,执行onTouchEvent事件
二、事件消费
onTouchEvent(MotionEvent ev)这个方法就是用来处理具体点击事件的,它是在dispatchTouchEvent方法中调用
它的返回值表示是否消费当前事件,也就是是否响应当前事件,具体逻辑如下:
如果return true 则会接收并消费该事件。
如果return false,那么这个事件会向上传递,并由上层 View 的 onTouchEvent 来接收,如果传递到上面的 onTouchEvent 还是返回 false,这个事件无效,且接收不到下一次事件。什么意思呢,我们来看一下运行效果,将ButtonTest的onTouchEvent方法设置返回false,其他的保持原本状态
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
Log.e("Touch = ", "chile onTouchEvent = " + event.getAction());
return false;
}
执行结果
10-20 07:29:57.526 10182-10182/com.mmf.ibinderdemo E/Touch =: group onInterceptTouchEvent 0
10-20 07:29:57.526 10182-10182/com.mmf.ibinderdemo E/Touch =: chile dispatchTouchEvent
10-20 07:29:57.526 10182-10182/com.mmf.ibinderdemo E/Touch =: chile onTouchEvent = 0
10-20 07:29:57.526 10182-10182/com.mmf.ibinderdemo E/Touch =: group onTouchEvent 0
10-20 07:29:57.526 10182-10182/com.mmf.ibinderdemo E/Touch =: group dispatchTouchEvent + true0
10-20 07:29:57.643 10182-10182/com.mmf.ibinderdemo E/Touch =: group onTouchEvent 1
10-20 07:29:57.643 10182-10182/com.mmf.ibinderdemo E/Touch =: group dispatchTouchEvent + true1
10-20 07:29:57.643 10182-10182/com.mmf.ibinderdemo E/MainActivity: lyt_test: grouptrue
将ButtonTest的onTouchEvent方法设置返回true,其他的保持原本状态
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
Log.e("Touch = ", "chile onTouchEvent = " + event.getAction());
return true;
}
执行结果
10-20 07:28:25.021 10118-10118/? E/libprocessgroup: failed to make and chown /acct/uid_10066: Read-only file system
10-20 07:28:34.403 10118-10118/com.mmf.ibinderdemo E/Touch =: group onInterceptTouchEvent 0
10-20 07:28:34.403 10118-10118/com.mmf.ibinderdemo E/Touch =: chile dispatchTouchEvent
10-20 07:28:34.403 10118-10118/com.mmf.ibinderdemo E/Touch =: chile onTouchEvent = 0
10-20 07:28:34.403 10118-10118/com.mmf.ibinderdemo E/Touch =: group dispatchTouchEvent + true0
10-20 07:28:34.530 10118-10118/com.mmf.ibinderdemo E/Touch =: group onInterceptTouchEvent 1
10-20 07:28:34.530 10118-10118/com.mmf.ibinderdemo E/Touch =: chile dispatchTouchEvent
10-20 07:28:34.530 10118-10118/com.mmf.ibinderdemo E/Touch =: chile onTouchEvent = 1
10-20 07:28:34.530 10118-10118/com.mmf.ibinderdemo E/Touch =: group dispatchTouchEvent + true1
10-20 07:28:34.531 10118-10118/com.mmf.ibinderdemo E/MainActivity: btn_test: chiletrue
从结果上看,当返回false时,ButtonTest的onTouchEvent方式只执行了一次down的事件,别的事件都不再执行,且GroupTest消费了事件
当返回true时,表示该事件被这个ButtonTest消费了,GroupTest都没听调过onTouchEvent方法,因为事件被消费不再向上传递
ps:事件对应的值
MotionEvent.ACTION_DOWN = 0
MotionEvent.ACTION_MOVE = 2
MotionEvent.ACTION_UP = 1
三、事件分发
dispatchTouchEvent(MotionEvent ev)
竟然最后一个说事件分发,顺序跟事件步骤相反,因为我觉得如果事件拦截和事件消费大概流程懂了,事件分发就会更好理解