事件触发接收后到View(ViewGroup)流程:
View.java -> 只处理事件(dispatchTounchEvent)
ViewGroup.java -> 容器分发事件 (dispatchTounchEvent)
setView()函数(ViewRootImpl.java)</br>
--> inputChannel = new InputChannel();
//接收 输入事件 (初始化 事件接收)
--> mInputEventReceiver = new WindowInputEventReceiver(inputChannel,Looper.myLooper());
--> onInputEvent(InputEvent event) (WindowInputEventReceiver.java 是 ViewRootImpl 的内部类)
--> enqueueInputEvent()
// enqueueInputEvent 最后一个参数传入的true
--> doProcessInputEvents();
--> deliverInputEvent(q)
--> stage.deliver(q); //(InputStage.java -> ViewPostImeInputStage.java)
--> onProcess(QueuedInputEvent q)
--> processPointerEvent(q);
//mView == DecorView
--> mView.dispatchPointerEvent(event);
--> dispatchPointerEvent(event)//( 由于DecorView 没有是实现方法,所以也就到了View 的此方法)
--> dispatchTouchEvent(event)//然后再到了 DecorView, 同时 此方法处理了与Activity 关联
/*
这是DecorView 的 dispatchTouchEvent 方法
mWindow = PhoneWindow
cb = Activity
然后就到了 Activity 的 dispatchTouchEvent 方法
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
getWindow().superDispatchTouchEvent(ev)(Activity.java)
//PhoneWindow 的 方法
--> mDecor.superDispatchTouchEvent(event);
//DecorView 的 superDispatchTouchEvent 方法
--> super.dispatchTouchEvent(event);
//由于 DecorView 自己没有处理方法 所以就转父亲 处理,FramLayout 并没有实现这个方法就继续向上走
--> ViewGroup的 dispatchTouchEvent() 方法
事件处理:
1.onTouch 与 onClick 执行顺序 和 关系
setOnTouchListener(OnTouchListener listener){
return true or false;
}
setOnClick(View view)
由上面 Touch 事件接收流程看出:
当点击 控件View 时 会到 View 中的 dispatchTouchEvent这个方法:
dispatchTouchEvent(MotionEvent event)(View.java)
// ListenerInfo 类的这个方法 处理OnTouch 回调
--> li.mOnTouchListener.onTouch(this, event)
分发后会执行
onTouchEvent(MotionEvent event)(View.java)
// 点击手指抬起后 (MotionEvent.ACTION_UP ),才会执行OnClick 方法
--> mPerformClick = new PerformClick()
--> performClickInternal()
//调用到 onClick
--> li.mOnClickListener.onClick(this);
当点击时 OnTouchListener 先执行
//如下 当 onTouch 返回false 是 result = false
//如果 OnTouch 返回True 是 result = true, 这是就不能回调 OnClick 事件,所以二者是冲突关系的
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
执行onClick 事件执行后表示事件消费了
2.onTouchEvent 在哪儿执行?
3.LongClick 执行?
onTouchEvent(MotionEvent event)(View.java)
//MotionEvent.ACTION_DOWN 长按时调用方法
/*
***注意 长按 LongClick,触发时间 在29 时 500ms, 30以后是 400ms***
TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS 延迟的时间
*/
--> checkForLongClick(
ViewConfiguration.getLongPressTimeout(),
x,
y,
TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS);
此时 是一个延迟操作,如果延迟没有达到时间(比如 500ms),那么就会移除长按时间变成 短按事件
4.按下View,移动手指,为什么 onClick 执行?
//手指按下 并且移动时, 移动到控件外不执行OnClick 事件
onTouchEvent(MotionEvent event)(View.java)
// 因为手指一动 需要看 Move 状态
/*
pointInView(x, y, touchSlop) 判断是否在控件上
*/
-->if (!pointInView(x, y, touchSlop)) {
// Outside button
// Remove any future long press/tap checks
removeTapCallback();//
removeLongPressCallback();
if ((mPrivateFlags & PFLAG_PRESSED) != 0) {
//设置后 onTouchEvent()方法中的MotionEvent.ACTION_UP 条件下(mPrivateFlags & PFLAG_PREPRESSED) != 0; 不满足
setPressed(false);
}
mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
}