Android触摸事件的处理概述

触摸消息事件从Activity的dispatchTouchEvent()开始,首先如果是down事件就会调用onUserinteraction。然后调用window.superDispatchTouch(),此window是PhoneWindow,而superDispatchTouch调用的就是DecorView的superDispatchTouch。而DecorView有时继承了FrameLayout,所以事件是从ViewGroup的dispatchTouchEvent()

Activity.class

 /**
     * Called to process touch screen events.  You can override this to
     * intercept all touch screen events before they are dispatched to the
     * window.  Be sure to call this implementation for touch screen events
     * that should be handled normally.
     * 
     * @param ev The touch screen event.
     * 
     * @return boolean Return true if this event was consumed.
     */
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

ViewGroup.class

dispatchTouchEvent:主要分发事件

/**
	 * ViewGroup.dispatchTouchEvent
	 * 
	 * @param ev
	 * @return
	 */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
            final int action = ev.getAction();
            final int actionMasked = action & MotionEvent.ACTION_MASK;

            // Handle an initial down.
            if (actionMasked == MotionEvent.ACTION_DOWN) {
                // Throw away all previous state when starting a new touch gesture.
                // The framework may have dropped the up or cancel event for the previous gesture
                // due to an app switch, ANR, or some other state change.
                cancelAndClearTouchTargets(ev);
                resetTouchState();
            }

            /**
             * 检查是否被截获
             */
            final boolean intercepted;
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || mFirstTouchTarget != null) {
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                if (!disallowIntercept) {
                    intercepted = onInterceptTouchEvent(ev);
                    ev.setAction(action); // restore action in case it was changed
                } else {
                    intercepted = false;
                }
            } else {
                // There are no touch targets and this action is not an initial down
                // so this view group continues to intercept touches.
                intercepted = true;
            }

            // Check for cancelation.
            final boolean canceled = resetCancelNextUpFlag(this)
                    || actionMasked == MotionEvent.ACTION_CANCEL;

            // Update list of touch targets for pointer down, if needed.
            final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
            TouchTarget newTouchTarget = null;
            boolean alreadyDispatchedToNewTouchTarget = false;
            /**
             * 如果没有被取消或者截获就去寻找子视图
             */
            if (!canceled && !intercepted) {
               ...
            }
            
            /**
             * 如果没有找到目标子视图
             */
            if (mFirstTouchTarget == null) {
                // No touch targets so treat this as an ordinary view.
                handled = dispatchTransformedTouchEvent(ev, canceled, null,
                        TouchTarget.ALL_POINTER_IDS);
            } else {
            	/**
            	 * 如果找到了目标子视图就开始分发
            	 */
                // Dispatch to touch targets, excluding the new touch target if we already
                // dispatched to it.  Cancel touch targets if necessary.
                TouchTarget predecessor = null;
                TouchTarget target = mFirstTouchTarget;
                while (target != null) {
                    final TouchTarget next = target.next;
                    if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
                        handled = true;
                    } else {
                        final boolean cancelChild = resetCancelNextUpFlag(target.child)
                                || intercepted;
                        if (dispatchTransformedTouchEvent(ev, cancelChild,
                                target.child, target.pointerIdBits)) {
                            handled = true;
                        }
                        if (cancelChild) {
                            if (predecessor == null) {
                                mFirstTouchTarget = next;
                            } else {
                                predecessor.next = next;
                            }
                            target.recycle();
                            target = next;
                            continue;
                        }
                    }
                    predecessor = target;
                    target = next;
                }
            }

            // Update list of touch targets for pointer up or cancel, if needed.
            if (canceled
                    || actionMasked == MotionEvent.ACTION_UP
                    || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
                resetTouchState();
            } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
                final int actionIndex = ev.getActionIndex();
                final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
                removePointersFromTouchTargets(idBitsToRemove);
            }
        }

        if (!handled && mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
        }
        return handled;
    }



/**
 * Transforms a motion event into the coordinate space of a particular child view,
 * filters out irrelevant pointer ids, and overrides its action if necessary.
 * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
 * 
 * 如果没有目标子视图就调用父类的dispatchTouchEvent,否则调用子视图的dispatchTouchEvent
 */
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
        View child, int desiredPointerIdBits) {
    final boolean handled;
    ...
    return handled;
}

onInterceptTouchEvent:拦截消息,决定来消费的View

   public boolean onInterceptTouchEvent(MotionEvent ev) {
        return false;
    }


View.class

    /**
     * 
     *View.dispatchTouchEvent
     */
    public boolean dispatchTouchEvent(MotionEvent event) {
    	...
        if (onFilterTouchEventForSecurity(event)) {
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            //如果设置了setOnTouchListener那么先有该listener处理,如果返回是true那就获取该View作为事件的处理者
            if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                return true;
            }
            //如果没有设置就直接调用View.onTouchEvent
            if (onTouchEvent(event)) {
                return true;
            }
        }
        return false;
    }

onTouchEvent:获取各个事件并产生onClick,onLongClick事件。

    public boolean onTouchEvent(MotionEvent event) {

    	...
    	/**
    	 * 如果设置有setTouchDelegate那么就先有代理的onTouchEvent处理
    	 */
        if (mTouchDelegate != null) {
            if (mTouchDelegate.onTouchEvent(event)) {
                return true;
            }
        }

    	/**
    	 * 1.判断如果是在可以被点击或长点击时才会去消耗该点击事件
    	 * 2.这里会触发点击和长按的事件
    	 */
        if (((viewFlags & CLICKABLE) == CLICKABLE ||
                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_UP:
                   ...
                    break;

                case MotionEvent.ACTION_DOWN:
                   ...
                    break;

                case MotionEvent.ACTION_CANCEL:
                   ...
                    break;

                case MotionEvent.ACTION_MOVE:
                    ...
                    break;
            }
            return true;
        }

        return false;
    }

你可能感兴趣的:(Android触摸事件的处理概述)