一、这里讲的是单点触摸,一个事件序列是由 down – move – up 组成
1、首先当手指点击屏幕的时候,Activity会拿到这个事件,经过一层一层的分发,最终才能到达View上。
// 这个就是Activity的dispatchTouchEvent方法
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
// 然后调用window 的 dispatchTouchEvent方法
// 也就是调用PhonWindow的superDispatchTouchEvent方法
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
2、调用DecorView 的 superDispatchTrackballEvent,最终就调用到ViewGroup的dispatchTouchEvent方法。
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
二、先讲事件的处理流程
1、事件的处理是从View的dispatchTouchEvent方法看起
textView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
当设置了TouchListener之后,这个 mListenerInfo 就会为null,假设onTouch方法返回true,那么这个View的OnClick事件就不会执行,因为 li.mOnTouchListener.onTouch(this, event) 返回为true,if成立,result = true 下面 onTouchEvent(event)就不会执行
2、如果onTouch返回为false,那么就会执行 onTouchEvent(event)方法,在MotionEvent.ACTION_UP的时候调用 performClickInternal()方法,最终调用 performClick()方法。
三、先讲事件的分法流程
1、假设有一下案例
// 第一层层级 — 总经理 —ViewGroup
// 第二层层级 — 总监 —ViewGroup
// 第一层层级 — 清洁 —View
当down 事件到达总经理身上的时候,假设自己拦截处理,也就是onInterceptTouchEvent方法返回为true,那么就调用这个方法 dispatchTransformedTouchEvent(ev, canceled, null,
TouchTarget.ALL_POINTER_IDS) 注意第三个参数为null
最终就调到View的dispatchTouchEvent来处理这个事件
2、当onInterceptTouchEvent 不拦截事件,那么就返回false,if (!canceled && !intercepted) {}就进入这个if语句中
调用dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)这个方法,传递的child也就是总监,然后调用总监的dispatchTouchEvent方法,然后在走一圈流程(又到了ViewGroup的dispatchTouchEvent方法中去),由于总监也没有处理,最终交给清洁工处理,清洁工实质是View,那么就调到View的dispatchTouchEvent方法中,假设View(清洁工)设置了 OnTouchListener监听,并且onTouch方法返回为true,那么看下下图
那么下面的if条件成立,mFirstTouchTarget 就等于newTouchTarget
但是 newTouchTarget.next 为null,然后跳出循环。
down事走完之后,就已经决定了由谁来处理这个事件
2、当move事件达到的时候,也还是先走总经理、和总监,但是不会分发事件了。先调用总经理的 dispatchTransformedTouchEvent方法,然后调用child.dispatchTouchEvent(event),这个child此时为总监,最后才调用到 清洁工的dispatchTouchEvent方法,也就是View的dispatchTouchEvent方法。
3、拦截流程,只能在move事件中处理
ViewPager中显示ListView,此时会有事件冲突。
内部拦截法,子View来处理
ListView代码
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
getParent().requestDisallowInterceptTouchEvent(true);
break;
}
case MotionEvent.ACTION_MOVE: {
int deltaX = x - mLastX;
int deltaY = y - mLastY;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
}
case MotionEvent.ACTION_UP: {
break;
}
default:
break;
}
mLastX = x;
mLastY = y;
return super.dispatchTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN){
super.onInterceptTouchEvent(event);
return false;
}
return true;
}
外部拦截法,父View来处理
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
mLastX = (int) event.getX();
mLastY = (int) event.getY();
break;
}
case MotionEvent.ACTION_MOVE: {
int deltaX = x - mLastX;
int deltaY = y - mLastY;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
return true;
}
break;
}
case MotionEvent.ACTION_UP: {
break;
}
default:
break;
}
return super.onInterceptTouchEvent(event);
}
当事件被ViewPager进行拦截的时候,ListView会调用Cancel事件,Cancel事件是: 当事件被上层拦截的时候才会触发