The Activity->ViewGroup event is sent from the Activity->ViewGroup event. The Activity->ViewGroup event is sent from the ViewGroup event.

[Android Event Distribution decryption – ViewGroup distribution] (Blog.csdn.net/qq_32865887…)

This article mainly introduces the View for the event processing, obviously in the dispatchTouchEvent() method, directly on the code (this article analysis source code based on Android 10, there are some variations in each version of the source, but the basic principle is the same) :

1.1 View.dispatchTouchEvent()

/** * source code analysis: view.dispatchTouchEvent () */
public boolean dispatchTouchEvent(MotionEvent event) {
        / /... Post only important code
        
        boolean result = false;

        / /...

        final int actionMasked = event.getActionMasked();
        if (actionMasked == MotionEvent.ACTION_DOWN) {
            // Stop sliding if there are nested slides
            stopNestedScroll();
        }
        // Check the security of events
        if (onFilterTouchEventForSecurity(event)) {
            // Check whether the View is enabled. Check whether the View processes scroll bar events
            Rerult =true if you are handling scrollbar events
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                result = true;
            }
            // Key analysis 1:
            GetListenerInfo () is assigned a value. There are a number of places that getListenerInfo() calls, and it can be assumed that the Listener interface is not empty
            In the setOnTouchListener(OnTouchListener l) method, it is not null as long as the subclass implements this method
            // Check whether View is enabled
            // Check whether the onTouch method of mOnTouchListener returns true
            // Conclusion: If the subclass calls the setOnTouchListener method and implements the mOnTouchListener interface onTouch() method returns true result=true
            ListenerInfo li = mListenerInfo;
            if(li ! =null&& li.mOnTouchListener ! =null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }
            If result=true, onTouchEvent() will not go
            if(! result && onTouchEvent(event)) { result =true; }}/ /...
        
        return result;
    }
Copy the code

1.2 View.onTouchEvent()

View.ontouchevent () */
public boolean onTouchEvent(MotionEvent event) {
        / /... Post only important code
        
        final float x = event.getX();
        final float y = event.getY();
        final int viewFlags = mViewFlags;
        final int action = event.getAction();
        // Check whether the View can be clicked (click, long click, content click)
        final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE
                || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
                || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;
        // A disabled View also consumes click events, but does not respond
        if ((viewFlags & ENABLED_MASK) == DISABLED) {
            if(action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) ! =0) {
                setPressed(false);
            }
            mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
            return clickable;
        }
        
        / /...
        // Judgment value 1: the control can be clicked to enter the switch judgment value 2: the control is suspended or can be long pressed
        if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
            switch (action) {
                 // a. If the current event = raise view (main analysis)
                case MotionEvent.ACTION_UP:
                       / /... After a series of judgments, omitted here
                       / / create PerformClick
                       if (mPerformClick == null) {
                             mPerformClick = new PerformClick();
                       }
                       // Execute performClick() performClickInternal calls performClick() ->> Analyze 1
                       performClickInternal();
                    / /...
                    mIgnoreNextUpEvent = false;
                    break;
                // b. If current event = Press View
                case MotionEvent.ACTION_DOWN:
                    / /... You know, a bunch of judgments
                    if (mPendingCheckForTap == null) {
                         mPendingCheckForTap = new CheckForTap();
                    }
                    mPendingCheckForTap.x = event.getX();
                    mPendingCheckForTap.y = event.getY();
                    // Execute the postDelayed method
                    postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                    } else {
                        / /...
                    }
                    break;
                // c. If the current event = end event (no human cause
                case MotionEvent.ACTION_CANCEL:
                    if (clickable) {
                        setPressed(false);
                    }
                    removeTapCallback();
                    removeLongPressCallback();
                    mInContextButtonPress = false;
                    mHasPerformedLongPress = false;
                    mIgnoreNextUpEvent = false;
                    mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
                    break;)// d. If current event = slide view
                case MotionEvent.ACTION_MOVE:
                    / /...
                    if(! pointInView(x, y, touchSlop)) {// 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;
}
PerformClick () */  
 public boolean performClick(a) {
 
        notifyAutofillManagerOnClick();
        
        final boolean result;
        final ListenerInfo li = mListenerInfo;
        if(li ! =null&& li.mOnClickListener ! =null) {
            // You can use this method to set click sounds
            playSoundEffect(SoundEffectConstants.CLICK);

            // If we register a click event for the control View with the setOnClickListener () method
            // Then the mOnClickListener variable will be assigned a value (i.e., not null)
            // Then onClick () is called back and performClick () returns true
            li.mOnClickListener.onClick(this);
            result = true;
        } else {
            result = false;
        }
        / /...
        return result;
    }    
Copy the code

1.3 Summary of View Event Handling

When the user clicks on the control:Key point: Execution of onTouch () takes precedence over onClick ()

1.4 case Demo

public class MainActivity extends AppCompatActivity {

    private Button btn_click;

    private static final String TAG = "MainActivity";

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

        btn_click = findViewById(R.id.btn_click);

        btn_click.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG, "onClick"); }}); btn_click.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e(TAG, "onTouch: " + event.getAction());

                return true; }}); }}Copy the code

The log is as follows: 1. OnTouch returns true

2021-03-18 14:54:12.109 18268-18268/com.enjoy.clickevent E/MainActivity: onTouch: 0
2021-03-18 14:54:12.132 18268-18268/com.enjoy.clickevent E/MainActivity: onTouch: 2
2021-03-18 14:54:12.182 18268-18268/com.enjoy.clickevent E/MainActivity: onTouch: 2
2021-03-18 14:54:12.194 18268-18268/com.enjoy.clickevent E/MainActivity: onTouch: 2
2021-03-18 14:54:12.195 18268-18268/com.enjoy.clickevent E/MainActivity: onTouch: 1
Copy the code

2. The onTouch returns false

2021-03-18 14:59:13.795 19243-19243/com.enjoy.clickevent E/MainActivity: onTouch: 0
2021-03-18 14:59:13.808 19243-19243/com.enjoy.clickevent E/MainActivity: onTouch: 2
2021-03-18 14:59:13.824 19243-19243/com.enjoy.clickevent E/MainActivity: onTouch: 2
2021-03-18 14:59:13.841 19243-19243/com.enjoy.clickevent E/MainActivity: onTouch: 2
2021-03-18 14:59:13.857 19243-19243/com.enjoy.clickevent E/MainActivity: onTouch: 2
2021-03-18 14:59:13.891 19243-19243/com.enjoy.clickevent E/MainActivity: onTouch: 2
2021-03-18 14:59:13.895 19243-19243/com.enjoy.clickevent E/MainActivity: onTouch: 2
2021-03-18 14:59:13.896 19243-19243/com.enjoy.clickevent E/MainActivity: onTouch: 1
2021-03-18 14:59:13.898 19243-19243/com.enjoy.clickevent E/MainActivity: onClick
Copy the code

I believe that you should have a general understanding of Android event distribution and processing, and finally summarize:

  1. Android event distribution is passed first to the ViewGroup and then from the ViewGroup to the View.

  2. In ViewGroup, onInterceptTouchEvent can be used to intercept event passing. OnInterceptTouchEvent returns true to disallow event passing to child views, false to disallow event passing to child Views. False is returned by default.

  3. Events are distributed at dispatchTouch() of the ViewGroup, and the ViewGroup is handled as a View if the child View does not.

  4. If the child View consumes the event passed, the ViewGroup will not receive any events.

If you want to further study also need to follow the source code to read a few times, can be combined with down and move events in various cases of analysis. I will also analyze the occurrence of the event later. If you find this article useful, please like and bookmark ✨.

The Android event distribution mechanism is the most comprehensive and easy to understand in history