@act262
2017-05-24T14:25:42.000000Z
字数 2602
阅读 1058
AndroidSource
触摸事件从硬件层产生,由系统分发至当前应用,再由当前应用分发到前台展示的Activity,其中Activity这一层不是必须的.
屏幕触摸 -> Activity -> Window -> RootView -> View
整个调用链中使用了责任链的设计模式,将事件一层一层往下传递,如果被下层处理了,就不会返回上层了,上层也就不需要处理了,如果下层也不处理,那么原路返回上层,让上层去处理这个事件.
Activity.java
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
// 下层没有消费掉事件,则交给自己的onTouchEvent处理
return onTouchEvent(ev);
}
public boolean onTouchEvent(MotionEvent event) {
if (mWindow.shouldCloseOnTouch(this, event)) {
finish();
return true;
}
return false;
}
Window.java
public abstract boolean superDispatchTouchEvent(MotionEvent event);
Window的具体实现类是PhoneWindow
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
这里的mDecor是DecorView extends FrameLayout
即ViewGroup
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
所以流程跳转到了ViewGroup的dispatchTouchEvent
方法
public boolean dispatchTouchEvent(MotionEvent ev) {
// ...
// ViewGroup的这里需要特殊处理拦截的处理
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
childView.dispatchTouchEvent();
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
&& ev.getAction() == MotionEvent.ACTION_DOWN
&& ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
&& isOnScrollbarThumb(ev.getX(), ev.getY())) {
return true;
}
return false;
}
public boolean onToucheEvent(MotionEvent ev) {
// 继承自View的onTouchEvent方法
}
最后是到最后子节点的View来处理或者不处理
public boolean dispatchTouchEvent(MotionEvent event) {
// ...
// 如果设置了OnTouchListener,则OnTouchListener可以优先处理
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
// 前面的OnTouchListener没有消费掉,那么就交给自己的onTouchEvent来来处理
if (!result && onTouchEvent(event)) {
result = true;
}
}
public boolean onTouchEvent(MotionEvent event) {
// ... 这里对点击,长按等处理
switch (action) {
case MotionEvent.ACTION_UP:
// ...
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
// 处理点击的情况,执行点击
if (!post(mPerformClick)) {
performClick();
}
if (mUnsetPressedState == null) {
mUnsetPressedState = new UnsetPressedState();
}
// 点击完后变成非按压状态
if (prepressed) {
postDelayed(mUnsetPressedState,ViewConfiguration.getPressedStateDuration());
} else if (!post(mUnsetPressedState)) {
// If the post failed, unpress right now
mUnsetPressedState.run();
}
break;
case MotionEvent.ACTION_DOWN:
// Not inside a scrolling container, so show the feedback right away
// 变成按压状态,同时检测是否变成长按状态
setPressed(true, x, y);
checkForLongClick(0, x, y);
// ...
// 默认是没有处理的,所以会给上层有机会处理
return false;
}
由最底层View返回是否消费掉事件