1. Event distribution of View

process
  1. dispatchTouchEvent():
  2. OnTouchListener — – > the onTouch method
  3. onTouchEvent
  4. An onClickListener — – > the onClick method

ListenerInfo


    static class ListenerInfo {
        /**
         * Listener used to dispatch focus change events.
         * This field should be made private, so it is hidden from the SDK.
         * {@hide} * /
        protected OnFocusChangeListener mOnFocusChangeListener;

        /** * Listeners for layout change events. */
        private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;

        protected OnScrollChangeListener mOnScrollChangeListener;

        /** * Listeners for attach events. */
        private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;

        /**
         * Listener used to dispatch click events.
         * This field should be made private, so it is hidden from the SDK.
         * {@hide} * /
        public OnClickListener mOnClickListener;

        /**
         * Listener used to dispatch long click events.
         * This field should be made private, so it is hidden from the SDK.
         * {@hide} * /
        protected OnLongClickListener mOnLongClickListener;

        /**
         * Listener used to dispatch context click events. This field should be made private, so it
         * is hidden from the SDK.
         * {@hide} * /
        protected OnContextClickListener mOnContextClickListener;

        /**
         * Listener used to build the context menu.
         * This field should be made private, so it is hidden from the SDK.
         * {@hide} * /
        protected OnCreateContextMenuListener mOnCreateContextMenuListener;

        private OnKeyListener mOnKeyListener;

        private OnTouchListener mOnTouchListener;

        private OnHoverListener mOnHoverListener;

        private OnGenericMotionListener mOnGenericMotionListener;

        private OnDragListener mOnDragListener;

        private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;

        OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;

        OnCapturedPointerListener mOnCapturedPointerListener;
    }
Copy the code

dispatchTouchEvent


    public boolean dispatchTouchEvent(MotionEvent event) {
        // If the event should be handled by accessibility focus first.
        if (event.isTargetAccessibilityFocus()) {
            // We don't have focus or no virtual descendant has it, do not handle the event.
            if(! isAccessibilityFocusedViewOrHost()) {return false;
            }
            // We have focus and got the event, then use normal event dispatch.
            event.setTargetAccessibilityFocus(false);
        }

        boolean result = false;

        if(mInputEventConsistencyVerifier ! =null) {
            mInputEventConsistencyVerifier.onTouchEvent(event, 0);
        }

        final int actionMasked = event.getActionMasked();
        if (actionMasked == MotionEvent.ACTION_DOWN) {
            // Defensive cleanup for new gesture
            stopNestedScroll();
        }

        if (onFilterTouchEventForSecurity(event)) {
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                result = true;
            }
            //noinspection SimplifiableIfStatement
            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; }}if(! result && mInputEventConsistencyVerifier ! =null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
        }

        // Clean up after nested scrolls if this is the end of a gesture;
        // also cancel it if we tried an ACTION_DOWN but we didn't want the rest
        // of the gesture.
        if(actionMasked == MotionEvent.ACTION_UP || actionMasked == MotionEvent.ACTION_CANCEL || (actionMasked == MotionEvent.ACTION_DOWN && ! result)) { stopNestedScroll(); }return result;
    }
Copy the code

onTouchEvent


/**
     * Implement this method to handle touch screen motion events.
     * <p>
     * If this method is used to detect click actions, it is recommended that
     * the actions be performed by implementing and calling
     * {@link #performClick()}. This will ensure consistent system behavior,
     * including:
     * <ul>
     * <li>obeying click sound preferences
     * <li>dispatching OnClickListener calls
     * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when
     * accessibility features are enabled
     * </ul>
     *
     * @param event The motion event.
     * @return True if the event was handled, false otherwise.
     */
    public boolean onTouchEvent(MotionEvent event) {
        final float x = event.getX();
        final float y = event.getY();
        final int viewFlags = mViewFlags;
        final int action = event.getAction();

        final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE
                || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
                || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;

        if ((viewFlags & ENABLED_MASK) == DISABLED) {
            if(action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) ! =0) {
                setPressed(false);
            }
            mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
            // A disabled view that is clickable still consumes the touch
            // events, it just doesn't respond to them.
            return clickable;
        }
        if(mTouchDelegate ! =null) {
            if (mTouchDelegate.onTouchEvent(event)) {
                return true; }}if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
            switch (action) {
                case MotionEvent.ACTION_UP:
                    mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
                    if ((viewFlags & TOOLTIP) == TOOLTIP) {
                        handleTooltipUp();
                    }
                    if(! clickable) { removeTapCallback(); removeLongPressCallback(); mInContextButtonPress =false;
                        mHasPerformedLongPress = false;
                        mIgnoreNextUpEvent = false;
                        break;
                    }
                    booleanprepressed = (mPrivateFlags & PFLAG_PREPRESSED) ! =0;
                    if((mPrivateFlags & PFLAG_PRESSED) ! =0 || prepressed) {
                        // take focus if we don't have it already and we should in
                        // touch mode.
                        boolean focusTaken = false;
                        if(isFocusable() && isFocusableInTouchMode() && ! isFocused()) { focusTaken = requestFocus(); }if (prepressed) {
                            // The button is being released before we actually
                            // showed it as pressed. Make it show the pressed
                            // state now (before scheduling the click) to ensure
                            // the user sees it.
                            setPressed(true, x, y);
                        }

                        if(! mHasPerformedLongPress && ! mIgnoreNextUpEvent) {// This is a tap, so remove the longpress check
                            removeLongPressCallback();

                            // Only perform take click actions if we were in the pressed state
                            if(! focusTaken) {// Use a Runnable and post this rather than calling
                                // performClick directly. This lets other visual state
                                // of the view update before click actions start.
                                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();
                        }

                        removeTapCallback();
                    }
                    mIgnoreNextUpEvent = false;
                    break;

                case MotionEvent.ACTION_DOWN:
                    if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) {
                        mPrivateFlags3 |= PFLAG3_FINGER_DOWN;
                    }
                    mHasPerformedLongPress = false;

                    if(! clickable) { checkForLongClick(0, x, y);
                        break;
                    }

                    if (performButtonActionOnTouchDown(event)) {
                        break;
                    }

                    // Walk up the hierarchy to determine if we're inside a scrolling container.
                    boolean isInScrollingContainer = isInScrollingContainer();

                    // For views inside a scrolling container, delay the pressed feedback for
                    // a short period in case this is a scroll.
                    if (isInScrollingContainer) {
                        mPrivateFlags |= PFLAG_PREPRESSED;
                        if (mPendingCheckForTap == null) {
                            mPendingCheckForTap = new CheckForTap();
                        }
                        mPendingCheckForTap.x = event.getX();
                        mPendingCheckForTap.y = event.getY();
                        postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                    } else {
                        // Not inside a scrolling container, so show the feedback right away
                        setPressed(true, x, y);
                        checkForLongClick(0, x, y);
                    }
                    break;

                case MotionEvent.ACTION_CANCEL:
                    if (clickable) {
                        setPressed(false);
                    }
                    removeTapCallback();
                    removeLongPressCallback();
                    mInContextButtonPress = false;
                    mHasPerformedLongPress = false;
                    mIgnoreNextUpEvent = false;
                    mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
                    break;

                case MotionEvent.ACTION_MOVE:
                    if (clickable) {
                        drawableHotspotChanged(x, y);
                    }

                    // Be lenient about moving outside of buttons
                    if(! pointInView(x, y, mTouchSlop)) {// Outside button
                        // Remove any future long press/tap checks
                        removeTapCallback();
                        removeLongPressCallback();
                        if((mPrivateFlags & PFLAG_PRESSED) ! =0) {
                            setPressed(false);
                        }
                        mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
                    }
                    break;
            }

            return true;
        }

        return false;
    }
Copy the code

performClick


   /**
     * Call this view's OnClickListener, if it is defined.  Performs all normal
     * actions associated with clicking: reporting accessibility event, playing
     * a sound, etc.
     *
     * @return True there was an assigned OnClickListener that was called, false
     *         otherwise is returned.
     */
    public boolean performClick(a) {
        final boolean result;
        final ListenerInfo li = mListenerInfo;
        if(li ! =null&& li.mOnClickListener ! =null) {
            playSoundEffect(SoundEffectConstants.CLICK);
            li.mOnClickListener.onClick(this);
            result = true;
        } else {
            result = false;
        }

        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);

        notifyEnterOrExitForAutoFillIfNeeded(true);

        return result;
    }
Copy the code

天安门事件

public class MyButton extends android.support.v7.widget.AppCompatButton { public MyButton(Context context) { super(context); } public MyButton(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.i("kpioneer", "dispatchTouchEvent:action--" + event.getAction()); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.i("kpioneer", "onTouchEvent:action--" + event.getAction()); return super.onTouchEvent(event); }}Copy the code

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;

/** * Created by Xionghu on 2018/6/5. * Desc: */

public class MainActivity extends Activity implements View.OnTouchListener.View.OnClickListener {

    private Button button1;
    private RelativeLayout layout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button1 = (Button)findViewById(R.id.button1);
        layout = (RelativeLayout)findViewById(R.id.layout);

        layout.setOnTouchListener(this);
        button1.setOnTouchListener(this);

        layout.setOnClickListener(this);
        button1.setOnClickListener(this);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        Log.i("kpioneer"."OnTouchListener:acton--"+event.getAction()+"----view:"+v);
        return false;
    }

    @Override
    public void onClick(View v) {
        Log.i("kpioneer"."OnClickListener----view:"+v); }}Copy the code

<? xml version="1.0" encoding="utf-8"? > <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/layout"
    >

    <com.haocai.eventdemo.MyButton
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="14dp"
        android:text="Button" />

</RelativeLayout>
Copy the code
Conclusion:
  1. Control Listener events are triggered in the order onTouch followed by onClick
  2. Control onTouch returns true, making the onClick event null – preventing the event from being delivered. Return false to pass the onClick event.
  3. If the onTouch method of onTouchListener returns true, the onTouchEvent in the View will not be called. Order dispatchTouchEvent – > onTouchListener return false – – > onTouchEvent
  4. If the view is disenable, the onTouchListener will not execute, but the onTouchEvent(event) method will
  5. OnTouchEvent triggers an onClick event in the ACTION_UP branch of onTouchListener–>onTouch returns true, consuming the event. OnTouchListener –>onTouch returns false and does not consume this event

2. Event distribution of ViewGroup+View

ViewGroup inherited the View

  1. dispatchTouchEvent()
  2. OnInterceptTouchEvent () (intercepting touches, ViewGroup only)
  3. onTouchEvent()
dispatchTouchEvent

  @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if(mInputEventConsistencyVerifier ! =null) {
            mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
        }

        // If the event targets the accessibility focused view and this is it, start
        // normal event dispatch. Maybe a descendant is what will handle the click.
        if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
            ev.setTargetAccessibilityFocus(false);
        }

        boolean handled = false;
        if (onFilterTouchEventForSecurity(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();
            }

            // Check for interception.
            final boolean intercepted;
            if(actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget ! =null) {
                final booleandisallowIntercept = (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;
            }

            // If intercepted, start normal event dispatch. Also if there is already
            // a view that is handling the gesture, do normal event dispatch.
            if(intercepted || mFirstTouchTarget ! =null) {
                ev.setTargetAccessibilityFocus(false);
            }

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

            // Update list of touch targets for pointer down, if needed.
            final booleansplit = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) ! =0;
            TouchTarget newTouchTarget = null;
            boolean alreadyDispatchedToNewTouchTarget = false;
            if(! canceled && ! intercepted) {// If the event is targeting accessiiblity focus we give it to the
                // view that has accessibility focus and if it does not handle it
                // we clear the flag and dispatch the event to all children as usual.
                // We are looking up the accessibility focused host to avoid keeping
                // state since these events are very rare.
                View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
                        ? findChildWithAccessibilityFocus() : null;

                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;

                    // Clean up earlier touch targets for this pointer id in case they
                    // have become out of sync.
                    removePointersFromTouchTargets(idBitsToAssign);

                    final int childrenCount = mChildrenCount;
                    if (newTouchTarget == null&& childrenCount ! =0) {
                        final float x = ev.getX(actionIndex);
                        final float y = ev.getY(actionIndex);
                        // Find a child that can receive the event.
                        // Scan children from front to back.
                        final ArrayList<View> preorderedList = buildTouchDispatchChildList();
                        final boolean customOrder = preorderedList == null
                                && isChildrenDrawingOrderEnabled();
                        final View[] children = mChildren;
                        for (int i = childrenCount - 1; i >= 0; i--) {
                            final int childIndex = getAndVerifyPreorderedIndex(
                                    childrenCount, i, customOrder);
                            final View child = getAndVerifyPreorderedView(
                                    preorderedList, children, childIndex);

                            // If there is a view that has accessibility focus we want it
                            // to get the event first and if not handled we will perform a
                            // normal dispatch. We may do a double iteration but this is
                            // safer given the timeframe.
                            if(childWithAccessibilityFocus ! =null) {
                                if(childWithAccessibilityFocus ! = child) {continue;
                                }
                                childWithAccessibilityFocus = null;
                                i = childrenCount - 1;
                            }

                            if(! canViewReceivePointerEvents(child) || ! isTransformedTouchPointInView(x, y, child,null)) {
                                ev.setTargetAccessibilityFocus(false);
                                continue;
                            }

                            newTouchTarget = getTouchTarget(child);
                            if(newTouchTarget ! =null) {
                                // Child is already receiving touch within its bounds.
                                // Give it the new pointer in addition to the ones it is handling.
                                newTouchTarget.pointerIdBits |= idBitsToAssign;
                                break;
                            }

                            resetCancelNextUpFlag(child);
                            if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                                // Child wants to receive touch within its bounds.
                                mLastTouchDownTime = ev.getDownTime();
                                if(preorderedList ! =null) {
                                    // childIndex points into presorted list, find original index
                                    for (int j = 0; j < childrenCount; j++) {
                                        if (children[childIndex] == mChildren[j]) {
                                            mLastTouchDownIndex = j;
                                            break; }}}else {
                                    mLastTouchDownIndex = childIndex;
                                }
                                mLastTouchDownX = ev.getX();
                                mLastTouchDownY = ev.getY();
                                newTouchTarget = addTouchTarget(child, idBitsToAssign);
                                alreadyDispatchedToNewTouchTarget = true;
                                break;
                            }

                            // The accessibility focus didn't handle the event, so clear
                            // the flag and do a normal dispatch to all children.
                            ev.setTargetAccessibilityFocus(false);
                        }
                        if(preorderedList ! =null) preorderedList.clear();
                    }

                    if (newTouchTarget == null&& mFirstTouchTarget ! =null) {
                        // Did not find a child to receive the event.
                        // Assign the pointer to the least recently added target.
                        newTouchTarget = mFirstTouchTarget;
                        while(newTouchTarget.next ! =null) { newTouchTarget = newTouchTarget.next; } newTouchTarget.pointerIdBits |= idBitsToAssign; }}}// Dispatch to touch targets.
            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;
    }
Copy the code
onInterceptTouchEvent

  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;
    }
Copy the code
The sample

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.RelativeLayout;

/** * Created by Xionghu on 2018/6/6. * Desc: */

public class MyRelativeLayout extends RelativeLayout {
    public MyRelativeLayout(Context context) {
        super(context);
    }

    public MyRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.i("kpioneer"."dispatchTouchEvent:action--"+ev.getAction()+"---view:MyRelativeLayout");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.i("kpioneer"."onInterceptTouchEvent:action--"+ev.getAction()+"---view:MyRelativeLayout");
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i("kpioneer"."onTouchEvent:action--"+event.getAction()+"---view:MyRelativeLayout");
        return super.onTouchEvent(event); }}Copy the code

Click on the Button


06-06 11:05:18. 340, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: DispatchTouchEvent: action - 0 - view: MyRelativeLayout 06-06 11:05:18. 340, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: OnInterceptTouchEvent: action - 0 - view: MyRelativeLayout 06-06 11:05:18. 340, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: DispatchTouchEvent: action - 0 06-06 11:05:18. 340, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: OnTouchListener:acton--0----view:com.haocai.eventdemo.MyButton{8e32527 VFED.. C.. . 0 and - 264186 # 7 f070022 app: id/for} 06-06 11:05:18. 340, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: OnTouchEvent: action - 0 06-06 11:05:18. 370, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: DispatchTouchEvent: action - 2 - view: MyRelativeLayout 06-06 11:05:18. 370, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: OnInterceptTouchEvent: action - 2 - view: MyRelativeLayout 06-06 11:05:18. 370, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: DispatchTouchEvent: action - 06-06 11:05:18. 2, 370, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: OnTouchListener:acton--2----view:com.haocai.eventdemo.MyButton{8e32527 VFED.. C.. . P.... 0 and - 264186 # 7 f070022 app: id/for} 06-06 11:05:18. 380, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: OnTouchEvent: action - 06-06 11:05:18. 2, 390, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: DispatchTouchEvent: action - 2 - view: MyRelativeLayout 06-06 11:05:18. 390, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: OnInterceptTouchEvent: action - 2 - view: MyRelativeLayout 06-06 11:05:18. 390, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: DispatchTouchEvent: action - 06-06 11:05:18. 2, 390, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: OnTouchListener:acton--2----view:com.haocai.eventdemo.MyButton{8e32527 VFED.. C.. . P.... 0 and - 264186 # 7 f070022 app: id/for} 06-06 11:05:18. 390, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: OnTouchEvent: action - 06-06 11:05:18. 2, 400, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: DispatchTouchEvent: action - 2 - view: MyRelativeLayout 06-06 11:05:18. 400, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: OnInterceptTouchEvent: action - 2 - view: MyRelativeLayout 06-06 11:05:18. 400, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: DispatchTouchEvent: action - 06-06 11:05:18. 2, 400, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: OnTouchListener:acton--2----view:com.haocai.eventdemo.MyButton{8e32527 VFED.. C.. . P.... 0 and - 264186 # 7 f070022 app: id/for} 06-06 11:05:18. 410, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: OnTouchEvent: action - 06-06 11:05:18. 2, 410, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: DispatchTouchEvent: action - 1 - - - the view: MyRelativeLayout 06-06 11:05:18. 410, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: OnInterceptTouchEvent: action - 1 - - - the view: MyRelativeLayout 06-06 11:05:18. 410, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: DispatchTouchEvent: action - 06-06 11:05:18. 1, 410, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: OnTouchListener:acton--1----view:com.haocai.eventdemo.MyButton{8e32527 VFED.. C.. . P.... 0 and - 264186 # 7 f070022 app: id/for} 06-06 11:05:18. 410, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: OnTouchEvent: action - 06-06 11:05:18. 1, 410, 27438-27438 / com. Haocai. Eventdemo I/kpioneer: OnClickListener----view:com.haocai.eventdemo.MyButton{8e32527 VFED.. C.. . P.... 0 and - 264186 # 7 f070022 app: id/for the}Copy the code
In this example, the Button event click:
  1. The parent container touches the event first
  2. ViewGroup order: DispatchTouchEvent –>onInterceptTouchevent–>dispatchTouchEvent (Button) –>OnTouchListener(Button) –>return false– > OnTouchEvent (Button) (consumable event) —– onTouchEvent (this sample parent layout is not called)