The original article was first published in the wechat public number: Practice, welcome to pay attention to communication!

In the previous article, the general process of Android event distribution was described. The methods related to events are introduced from three aspects: Activity, ViewGroup and View, as follows:

  1. Activity
  2. ViewGroup
  3. View

Read this article first:

  • The foundation of Android event distribution

Activity

The two main event passing methods in an Activity, dispatchTouchEvent() and onTouchEvent(), begin with the Activity’s dispatchTouchEvent() method.

Dispatching events

Activity dispatchTounchEvent()

 
// Event distribution
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        / / short method
        onUserInteraction();
    }
    if (getWindow().superDispatchTouchEvent(ev)) {
        return true;
    }
    The onTouchEvent() method returns false by default
    return onTouchEvent(ev);
}
Copy the code

The code above clearly handles only ACTION_DOWN events, indicating that ACTION_DOWN events trigger event distribution, and then calls the superDispatchTouchEvent(EV) method of the Window class, which is an abstract method. PhoneWindow: PhoneWindow: superDispatchTouchEvent(EV) : PhoneWindow: PhoneWindow: superDispatchTouchEvent(EV)

// An abstract method in the Window class
public abstract boolean superDispatchTouchEvent(MotionEvent event);
//Window subclass PhoneWindow superDispatchTouchEvent()
@Override  
public boolean superDispatchTouchEvent(MotionEvent event) {  
    return mDecor.superDispatchTouchEvent(event);  
}
Copy the code

. Obviously, there are calls the mDecor superDispatchTouchEvent (event), mDecor is a PhoneWindow DecorView object, which is the top view of the window. This is the root view of a real Activity, it inherits FrameLayout, and with super.dispatchTouchEvent, it sends touchEvents to the child views of each Activity. This is the view we set when setContentView is set in the activity. onCreat method.

/ / DecorView class declaration
private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {...public boolean superDispatchTouchEvent(MotionEvent event) {
        // The dispatchTouchEvent method from FrameLayout is called
        return super.dispatchTouchEvent(event); }... }Copy the code

Since FrameLayout doesn’t override the dispatchTouchEvent(Event) method, we need the FrameLayout parent, which is the implementation of this method in ViewGroup, to do the actual event distribution, The specific event distribution process here needs to be studied.

The event processing

The event handler in the Activity: onTouchEvent()

// Event handling, false is returned by default
public boolean onTouchEvent(MotionEvent event) {
        if (mWindow.shouldCloseOnTouch(this, event)) {
            finish();
            return true;
        }
        // Returns false by default
        return false;
    }
Copy the code

Because for the onTouchEvent() method, event passing is passed to the parent control, even if false is returned, the event is consumed.

Note: When an Activity dispatches an event, the event is propagated only if the Activity returns super.dispatchTouchEvent(EV). Either true or false will consume the event, terminating propagation of the event.

ViewGroup

There are three main event-passing methods in ViewGroup: dispatchTouchEvent(), onInterceptTouchEvent(), and onTouchEvent().

Dispatching events

DispatchTouchEvent () = dispatchTouchEvent();

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {...The dispatchTouchEvent() method returns false by default
    boolean handled = false;
    
    // The method determines whether to intercept the distribution of the eventonInterceptTouchEvent(ev); .Canceled and intercepted are false by default
    if(! canceled && ! intercepted) { ...// This method passes the event to the child View
        dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
        ...        
    }
            
    return handled;
}
Copy the code

So what this method does is it iterates through the child views in the ViewGroup, passing the event (ACTION_DOWN) to the child View for processing, Inside the main call onInterceptTouchEvent () and dispatchTransformedTouchEvent () method, onInterceptTouchEvent () returns false by default, Below is dispatchTransformedTouchEvent () method of the main source is as follows:

private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
            View child, int desiredPointerIdBits){...if (child == null) {
        handled = super.dispatchTouchEvent(event);
    } else {
        // Perform event distribution for subviewshandled = child.dispatchTouchEvent(event); }...return handled;
}
Copy the code

Obviously, dispatchTransformedTouchEvent () method is mainly for child View event distribution, if there is no child View, then call the parent View dispatchTouchEvent (event) method.

Events to intercept

The onInterceptTouchEvent() method in ViewGroup is provided as follows:

public boolean onInterceptTouchEvent(MotionEvent ev) {...// Returns false by default
    return false;
}
Copy the code

This method returns false by default, meaning that event distribution to child views is not intercepted, and is called in the dispatchTouchEvent() method of the ViewGroup.

The event processing

ViewGroup does not have its own onTouchEvent() event handling method. The event handling method of the ViewGroup is the event handling method of the View, which is as follows:

public boolean onTouchEvent(MotionEvent event) {...// Returns false by default
    return false;
}
Copy the code

This method handles related events. If it returns true, the event was handled. The usage is described below.

View

There are two main event distribution methods in View: dispatchTouchEvent() and onTouchEvent(), which are as follows:

Dispatching events

The event distribution method in the View is dispatchTouchEvent(). The main code is as follows:

public boolean dispatchTouchEvent(MotionEvent event) {...// Default return value is false
    boolean result = false; .if (onFilterTouchEventForSecurity(event)) {
        ...
        // The onTouchEvent method is called
        if(! result && onTouchEvent(event)) { result =true; }}...return result;   
}

Copy the code

In the above code, the default return value of dispatchTouchEvent() is false, indicating that the event continues to be dispatched. In fact, the return value of dispatchTouchEvent is related to the return value of onTouchEvent. If onTouchEvent returns true, result of dispatchTouchEvent is true, then the event has been consumed. If onTouchEvent is true, then the event has been consumed. Here are the conditions under which the ontouchEvent method is executed:

public boolean onFilterTouchEventForSecurity(MotionEvent event) {
    //noinspection RedundantIfStatement
    if((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) ! =0&& (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) ! =0) {
        // Window blocked, drop touch event (rarely executed)
        return false;
    }
    return true;
}
Copy the code

Obviously, the above method must return true in the general case, so it must execute to the onTouchEvent method. The dispatchTouchEvent method calling the View can actually be shortened as follows:

public boolean dispatchTouchEvent(MotionEvent event) {...// Default return value is false
    boolean result = false; .return onTouchEvent(event)
}
Copy the code
The event processing

The event distribution method in the View is onTouchEvent(). The main code is as follows:

public boolean onTouchEvent(MotionEvent event) {...// Return true if the TouchDelegate defaults to empty, which is mainly about the touch region of the View
    if(mTouchDelegate ! =null) {
        if (mTouchDelegate.onTouchEvent(event)) {
            return true; }}// This condition returns true if the click event is set
    if (((viewFlags & CLICKABLE) == CLICKABLE ||
            (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
            (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
        switch (action) {
           // Handle each event. }return true;
    }
    // By default, false is returned, indicating that no event is consumed
    return false;
}

Copy the code

When an event is passed to a child View, it can either be consumed by the current View, or it can be passed back up without consuming time. If the Activity is not intercepted or processed, the event will be discarded.

This article, the second in Android event distribution, documents event-related methods in activities, ViewGroups, and Views. The dispatchTouchEvent(), onTouchEvent(), and onInterceptTouchEvent() methods behave differently in activities, viewGroups, and views. Understanding the relationship between events in Android from a code point of view, the event distribution process will be covered in the next article. Personal wechat public number: practice can exchange learning together!