在项目中,经常遇到事件冲突,ScrollView,ViewPager滑动卡顿等情况,比如:onClick和onLongClick事件冲突,dispatchTouchEvent,onInterceptTouchEvent这些方法都有一个boolean返回值,不同返回值事件处理机制是不同的。
一:事件分发流程
1:现在有一个场景,用户长按button,我们希望只触发onLongClick,然而onClick事件也触发了.
这种情况比如简单,直接在onLongClick返回true就可以解决了,返回true表示onLongClick消费了这次事件。
2:view 和 viewGroup的介绍
View是所有UI组件的基类(如:TextView,Button,ImageView),而 ViewGroup是容纳这些组件的容器(如:LinearLayout,ReltiveLayout),ViewGroup是View派生出来的.
view有dispatchTouchEvent,onTouchEvent这两个方法,ViewGroup多了一个onInterceptTouchEvent方法,此方法决定触发事件是自己处理,还是分发给下一个组件处理.
2:事件涉及到的常用方法
用户点击屏幕时,将触发viewGroup的dispatchTouchEvent(MotionEvent ev)、onInterceptTouchEvent(MotionEvent ev)、onTouchEvent(MotionEvent ev);
3:方法返回值介绍
dispatchTouchEvent是处理触摸事件分发,事件(多数情况)是从Activity的dispatchTouchEvent开始的。执行super.dispatchTouchEvent(ev),事件向下分发。
onInterceptTouchEvent是ViewGroup提供的方法,默认返回false,返回true表示拦截,返回true后,由该类的onTouchEvent方法来执行。
onTouchEvent是View中提供的方法,ViewGroup也有这个方法,view中不提供onInterceptTouchEvent。view中默认返回true,表示消费了这个事件。
二:举一个栗子
1 老板将一个任务分配给经理,经理将任务分配给员工去完成,员工完成后,将结果反馈给经理,经理将任务结果反馈给老板,这是默认流程。
默认流程dispatchTouchEvent(MotionEvent ev)、onInterceptTouchEvent(MotionEvent ev)、onTouchEvent(MotionEvent ev),全部返回super.xxxxxxx
输出日志的结果
10-15 20:13:31.600 8716-8716/com.activity E/info: BossView dispatchTouchEvent() boss create task!10-15 20:13:31.600 8716-8716/com.activity E/info: BossView onInterceptTouchEvent() boss将task 分配给manager
10-15 20:13:31.600 8716-8716/com.activity I/info: ManagerView 经理让onInterceptTouchEvent决定任务由谁完成
10-15 20:13:31.600 8716-8716/com.activity I/info: ManagerView onInterceptTouchEvent()经理接收到任务,将任务分配给员工
10-15 20:13:31.601 8716-8716/com.activity I/info: EmployeesView 员工开始工作.
10-15 20:13:31.601 8716-8716/com.activity I/info: EmployeesView 员工圆满完成任务.
10-15 20:13:31.602 8716-8716/com.activity I/info: ManagerView onTouchEvent() 经理验收任务结果,并向老板报告
10-15 20:13:31.602 8716-8716/com.activity E/info: BossView onTouchEvent() 工作已经完毕
2 老板将一个任务分配给经理,经理将任务分配给员工去完成,员工觉得难度大,无法完成(onTouchEvent返回true),由于老板没有接收到工作报告,会不停向经理分发任务(managerView的dispatchTouchEvent方法将不停被调用,员工的dispatchTouchEvent方法也会被继续调用)。
输出日志:
3 老板将一个任务分配给经理,因为上一次任务,经理并未收到员工的工作报告,所以这次经理决定,自己的来本次完成,将事件直接消费(onInterceptTouchEvent返回true),不分给员工去做,让员工一边凉快去 。
日志输出:
10-15 22:11:26.877 22219-22219/com.activity I/info: MainActivity--dispatchTouchEvent()ACTION_DOWN10-15 22:11:26.878 22219-22219/com.activity E/info: BossView dispatchTouchEvent() boss create task!
10-15 22:11:26.879 22219-22219/com.activity E/info: BossView onInterceptTouchEvent() boss将task 分配给manager
10-15 22:11:26.879 22219-22219/com.activity I/info: ManagerView 经理让onInterceptTouchEvent决定任务由谁完成
10-15 22:11:26.879 22219-22219/com.activity I/info: ManagerView onInterceptTouchEvent()经理接收到任务安排,员工做得不好,自己来做任务
10-15 22:11:26.879 22219-22219/com.activity I/info: ManagerView onTouchEvent() 经理验收任务结果,并向老板报告
10-15 22:11:26.879 22219-22219/com.activity E/info: BossView onTouchEvent() 工作已经完毕
10-15 22:11:26.886 22219-22219/com.activity I/info: MainActivity--dispatchTouchEvent()ACTION_MOVE
10-15 22:11:26.902 22219-22219/com.activity I/info: MainActivity--dispatchTouchEvent()ACTION_MOVE
10-15 22:11:26.912 22219-22219/com.activity I/info: MainActivity--dispatchTouchEvent()ACTION_MOVE
10-15 22:11:26.919 22219-22219/com.activity I/info: MainActivity--dispatchTouchEvent()ACTION_MOVE
10-15 22:11:26.921 22219-22219/com.activity I/info: MainActivity--dispatchTouchEvent()ACTION_UP
三:代码
由于代码差不多,这里只贴出ManagerView的代码,完整代码下载连接在文章下方
public class ManagerView extends LinearLayout {
private final String TAG="ManagerView ";
private int index=0;
public ManagerView(Context context) {
super(context);
}
public ManagerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(index==0){
Log.i("info",TAG+" onTouchEvent() 经理验收任务结果,并向老板报告");
}else{
Log.i("info",TAG+" onTouchEvent() 自己亲自来完成任务");
}
return super.onTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
index = 0;
// if(index==0){
// Log.i("info",TAG+"onInterceptTouchEvent()经理接收到任务,将任务分配给员工");
// return super.onInterceptTouchEvent(ev);
// }else{
Log.i("info",TAG+"onInterceptTouchEvent()经理接收到任务安排,员工做得不好,自己来做任务");
return true;
// }
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i("info",TAG+"经理让onInterceptTouchEvent决定任务由谁完成");
return super.dispatchTouchEvent(ev);
}
}
备注:上传代码时,我电脑github出了点小问题,如果代码有问题,请留言,代码下载地址:github