在Android中Touch触摸事件主要包括点击(onClick)、长按(onLongClick)、拖拽(onDrag)、滑动(onScroll)等
- 按下(ACTION_DOWN)
- 移动(ACTION_MOVE)
- 抬起(ACTION_UP)
- 取消手势(ACTION_CANCEL)
- 滑出屏幕(ACTION_OUTSIDE)
开始
当屏幕被触摸,Linux内核会将硬件产生的触摸事件包装为Event存到/dev/input/event[x]目录下
接着,系统创建的一个InputReaderThread线程loop起来让EventHub调用getEvent()不断的从/dev/input/文件夹下读取输入事件
然后InputReader则从EventHub中获得事件交给InputDispatch。
而InputDispatch又会把事件分发到需要的地方,比如ViewRootImpl的WindowInputEventReceiver中。
然后就调用了ViewRootImpl.enqueueInputEvent()
一波三折后,最终调用了DecorView.dispatchPointerEvent,
1 2 3 4 5 6 7 |
private int processPointerEvent(QueuedInputEvent q) {
...
// mView是decorview
boolean handled = mView.dispatchPointerEvent(event);
...
return handled ? FINISH_HANDLED : FORWARD;
} |
然后在调用了Activity的dispatchTouchEvent(ev),这就是一开始的大致流程
1 2 3 4 5 6 7 8 9 |
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// 这里的window 就是 phoneWindow , callback 就是对应 activity
// 也就是最终调用了 Window.cb.dispatchTouchEvent(ev)
// 也就是activity的dispatchTouchEvent
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
} |
Actvity
dispatchTouchEvent方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
// 这个方法,基本上每次有触摸或者键盘事件的时候,都会触发该方法;
// 目前是个空方法
onUserInteraction();
}
// 这里就会通过PhoneWindow调用了Decorview.superDispatchTouchEvent(event)
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
// 这样就我们经常说的,如果View返回true的话
// 就会调用activity的onTouchEvent(ev)方法
return onTouchEvent(ev);
} |
ViewGroup
dispatchTouchEvent(event)方法十分长,这里只保留重要的分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
...
boolean handled = false; // 开始是默认不处理 false
//// 是否过滤掉该事件 , 也就是判断这个事件的点,有没有超出屏幕或者这个窗口被遮住了
if (onFilterTouchEventForSecurity(ev)) {
// 记录 action , actionMask
final int action = ev.getAction();
final int actionMasked = action & MotionEvent.ACTION_MASK;
// 如果是按下操作
if (actionMasked == MotionEvent.ACTION_DOWN) {
// 把之前的一些状态,重置,
// 如果之前mFirstTouchTarget不是空,发送cancel事件出去
// 重置之前的mFirstTouchTarget为空
cancelAndClearTouchTargets(ev);
resetTouchState();
}
// ViewGroup才有的,是否拦截事件
final boolean intercepted;
// 如果事件类型ACTION_DOWN或者mFirstTouchTarget不为空 才有机会触发onInterceptTouchEvent方法
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
// disallowIntercept 就是我们是否跳过这次的拦截事件
// 子类可以调用equestDisallowInterceptTouchEvent 为方法true跳过拦截
//但是对DOWN无效,因为DOWN会在开始重置状态
// 如果是true,那这次的拦截事件不用管,
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
// false 走正常流程
// onInterceptTouchEvent(ev) 是否拦截
intercepted = onInterceptTouchEvent(ev);
// 因为有可能,会拦截该事件,所以要重新setAction
ev.setAction(action);
} else {
//disallowIntercept 是true ,跳过拦截事件,所以没有拦截
intercepted = false;
}
} else {
// 其他的情况都要拦截
intercepted = true;
}
// 如果是onInterceptTouchEvent为true引起的拦截,取消target的焦点
if (intercepted || mFirstTouchTarget != null) {
ev.setTargetAccessibilityFocus(false);
}
// 判断是否cancel,一个是事件,一个是View的flag
final boolean canceled = resetCancelNextUpFlag(this)
|| actionMasked == MotionEvent.ACTION_CANCEL;
// 如果不取消,也不拦截
if (!canceled && !intercepted) {
// 如果是DOWN相关
if (actionMasked == MotionEvent.ACTION_DOWN
|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
final int actionIndex = ev.getActionIndex(); // always 0 for down
final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
: TouchTarget.ALL_POINTER_IDS;
... 找到接收Touch事件的子View
newTouchTarget = getTouchTarget(child);
if (newTouchTarget != null) {
// 如果不是空,跳出循环,说名找到了
newTouchTarget.pointerIdBits |= idBitsToAssign;
break;
}
resetCancelNextUpFlag(child);
// 否则通过dispatchTransformedTouchEvent方法找
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
... 最后把addTouchTarget添加child进去,mFirstTouchTarget不为空
newTouchTarget = addTouchTarget(child, idBitsToAssign);
// 此时alreadyDispatchedToNewTouchTarget为true说明已经分发过事件
alreadyDispatchedToNewTouchTarget = true;
break;
}
...
}
// 如果mFirstTouchTarget还是空,说明没有子VIew返回true,那自己处理
if (mFirstTouchTarget == null) {
// No touch targets so treat this as an ordinary view.
handled = dispatchTransformedTouchEvent(ev, canceled, null,
TouchTarget.ALL_POINTER_IDS);
} else {
...
while (target != null) {
final TouchTarget next = target.next;
// 这个基本是对应DOWN 分化过的,直接返回true
if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
handled = true;
} else {
// 可能是是拦截
final boolean cancelChild = resetCancelNextUpFlag(target.child)
|| intercepted;
// 否则一个一个的分发下去
if (dispatchTransformedTouchEvent(ev, cancelChild,
target.child, target.pointerIdBits)) {
handled = true;
...
return handled;
} |
进入dispatchTransformedTouchEvent方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits) {
final boolean handled;
// 如果是取消,发送cancel事件
final int oldAction = event.getAction();
if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
event.setAction(MotionEvent.ACTION_CANCEL);
if (child == null) {
handled = super.dispatchTouchEvent(event);
} else {
handled = child.dispatchTouchEvent(event);
}
event.setAction(oldAction);
return handled;
}
...
if (child == null) {
// 如果是空,则调用父类
handled = super.dispatchTouchEvent(transformedEvent);
} else {
final float offsetX = mScrollX - child.mLeft;
final float offsetY = mScrollY - child.mTop;
transformedEvent.offsetLocation(offsetX, offsetY);
if (! child.hasIdentityMatrix()) {
transformedEvent.transform(child.getInverseMatrix());
}
// 否则调用本身
handled = child.dispatchTouchEvent(transformedEvent);
}
// Done.
transformedEvent.recycle();
return handled;
} |
View
最后到View中的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
public boolean dispatchTouchEvent(MotionEvent event) {
...
final int actionMasked = event.getActionMasked();
if (actionMasked == MotionEvent.ACTION_DOWN) {
// 如果是按下,停止滑动
stopNestedScroll();
}
// 重写onFilterTouchEventForSecurity方法可以跳过touch事件
if (onFilterTouchEventForSecurity(event)) {
if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
result = true;
}
// 这里就是如果设置 OnTouchListener 的方法的话,也返回了true,就会跳过onTouchEvent方法
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
// 最后调用onTouchEvent方法
if (!result && onTouchEvent(event)) {
result = true;
}
}
// 松手或者取消时候 停止滑动
if (actionMasked == MotionEvent.ACTION_UP ||
actionMasked == MotionEvent.ACTION_CANCEL ||
(actionMasked == MotionEvent.ACTION_DOWN && !result)) {
stopNestedScroll();
}
return result;
} |
onTouchEvent
主要是针对按下,抬起,等一些列判断,认为是点击,还是长按等操作