1.大致单线流程
起点—>Activity的dispatchTouchEvent(不是由java层调用的.由C++.Activity驱动去做的.做完之后首先调用这里)
/**
* 屏幕触控事件分发Java层入口
* 不是由java层调用的.由C层Activity驱动去做的.做完之后首先调用这里
* 调用来处理触摸屏事件。您可以将此重写为在将所有触摸屏事件发送到窗口
* 请务必将此实现称为触摸屏事件应该正常处理。
* @param ev 触摸屏事件.
* @return boolean 返回 true 该事件被消耗.
*/
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
//按下的时候提供用户调用的业务
onUserInteraction();//这里面什么都没有
}
//这里的getWindow就是获取的抽象类Window的子类PhoneWindow
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
途经—>PhoneWindow的superDispatchTouchEvent(ev)
public boolean superDispatchTouchEvent(MotionEvent event) {
//DecorView--->superDispatchTouchEvent(event)
return mDecor.superDispatchTouchEvent(event);
}
途经—>DecorView的superDispatchTouchEvent(event)
public boolean superDispatchTouchEvent(MotionEvent event) {
//ViewGroup--->dispatchTouchEvent(event)
return super.dispatchTouchEvent(event);
}
途经—>ViewGroup的dispatchTouchEvent(event) 核心功能
/**
* 事件分发的核心功能就是这里面做的事情
* */
public boolean dispatchTouchEvent(MotionEvent ev) {
//辅助功能、残障、跨进程
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
}
...
---------↓↓↓---------
1.辅助功能、残障
2.是否启用拦截器(通过设置ViewGroup的requestDisallowInterceptTouchEvent(true)实现拦截)
2.1.拦截--->super.dispatchTouchEvent,(super代表自己的View,自己消费掉,不给childView)
2.2.不拦截--->找到需要响应的子view.dispatchTouchEvent(view代表下面子View)
总结:设置拦截代表拦截子view的触摸事件分发,不设置拦截则可让触控分发到下面的子view
(不拦截情况下第一次执行:如第一次按下--->直接分发给childView)
2.2.1.获取到当前操作点下面的所有子View,按View层级排列,取出顶层View
2.2.2.顶层View.dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)事件开始分发
2.2.3.if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {}
(不拦截情况下第二次执行:如第一次按下之后的拖动--->等待判断后再决定是否分发给childView)
if(!childView.OnTouch的return返回值){<---这里比较第一次多了一个判断
2.2.1.获取到当前操作点下面的所有子View,按View层级排列,取出顶层View
2.2.2.顶层View.dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)事件开始分发
2.2.3.if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {}
} else {
执行2.1拦截业务
}
总结:
1.其实我们设置的view.setOnTouchListener的onTouch()的return为false则表示还需要分发给我,下次可以响应继续onTouch,
2.其实我们设置的view.setOnTouchListener的onTouch()的return为true则表示我不需要分发给我了,下次别来了,你自己处理把,就是等用于我设置了我自己的拦截,执行2.1
所有的功能有很多.这里只是把核心的分发机制记录一下
---------↑↑↑---------
...
if (!handled && mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
}
return handled;
}
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,View child, int desiredPointerIdBits) {
...
//调子View--->dispatchTouchEvent(event)
handled = child.dispatchTouchEvent(event);
...
}
途经—>View—>dispatchTouchEvent(event)
public boolean dispatchTouchEvent(MotionEvent event) {
...
//li.mOnTouchListener.onTouch(this, event):调用我们对View设置的setOnTouchListener(listener)
if (li != null && li.mOnTouchListener != null&& (mViewFlags & ENABLED_MASK) == ENABLED&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
//上边当调用我们设置的OnTouchListener的onTouch返回=true时下边的onTouchEvent(event)就不会调用
if (!result && onTouchEvent(event)) {
result = true;
}
...
}
public boolean onTouchEvent(MotionEvent event) {
...以下伪代码:View的 单击、长按 ...等 都是在这里分发调用的
switch(event.getAction()){
case:MotionEvent.ACTION_UP:
break;
case:MotionEvent.ACTION_DOWN:
break;
case:MotionEvent.ACTION_MOVE:
break;
case:MotionEvent.ACTION_CANCEL:
break;
}
...
}
终点—>setOnTouchListener(listener)的listener
至此成功调用用户设置OnTouchListener的—>OnTouch()
归纳:Activity—>PhoneWindow—>DecorView—>ViewGroup—>View—>我们设置在View上的OnTouchListener