在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
主要是针对按下,抬起,等一些列判断,认为是点击,还是长按等操作