1. Three important ways

Pseudocode for three relationships

public boolean dispatchTouchEvent(MotionEvent event){
    boolean consume = false;
    if( onInterceptTouchEvent(event) ){
        consume = onTouchEvent(event);
    }else{
        consume = child.dispatchTouchEvent(event);
    }
    return consume;
}
Copy the code

1.1 Event distribution: dispatchTouchEvent(MotionEvent Event)

For event distribution;

The return value indicates whether or not the event will be distributed. The default return value is the return value of the subview’s dispatchTouchEvent().

OnInterceptTouchEvent (MotionEvent Event)

To determine whether to intercept a sequence of events;

Returns a value indicating whether to intercept the event.

1.3 Event handling: onTouchEvent(MotionEvent Event)

For handling events;

Returns a value indicating whether the event will be consumed.

If not, then the current View cannot receive the event event again for the same sequence of events. In this case, the event is no longer called

2. Special circumstances

  1. If the current View has an OnTouchListener set, the onTouch() method of the OnTouchListener will be called first when the event distributes the current View.

  2. If OnTouchListener (onTouch()) returns false, then “onTouchEvent()” is called; If return true, “onTouchEvent()” is not called;

  3. In “onTouchEvent()”, if the View sets OnClickListener, then [onClick()] will be called last. This method has the lowest priority and is the end of event passing.

3. Event distribution & Processing flowchart

graph TD Z(activity.dispatchTouchEvent) --> A(ViewGroupA.dispatchTouchEvent) A --> B(ViewGroupA.onInterceptTouchEvent) B -- -- > C {whether the return value to intercept} C - > | true: intercept | D (ViewGroupA. OnTouchEvent) C - > | false by default: don't intercept | E (ViewGroupB. DispatchTouchEvent) E - > F (ViewGroupB onInterceptTouchEvent) F - > {whether the return value to intercept} H H - > | true: intercept | I (ViewGroupB. OnTouchEvent) H - > | Default false: no intercept | J (ViewC dispatchTouchEvent) J - > K {ViewC whether set onTouchListener} K - > | | no M (ViewC. OnTouchEvent) K - > | Have | L {ViewC. OnTouchListener. The onTouch} L - > default false | | M L - > | true | N/distribute over processed & M - > O {} whether consumption O - > | return false | Q (return to the superior view onTouchEvent) O - > | view the default true | P/distribute over processed & Q -- -- > I I - > > S} {whether consumption S | ViewGroup default return false | D S -- - > | true | T/distribute over processed & D - > U {} whether consumption U - > | true | W/distribute over processed & U - > | | ViewGroup default return false V(activity.onTouchEvent) V --> X

4. Summary of the event (first, followed by test verification)

  1. The same sequence of events:

    This is from the moment the finger touches the screen to the moment it leaves the screen. It starts with ACTION_DOWN and ends with ACTION_UP, with 0 or ∞ ACTION_MOVE in betweenCopy the code
  2. Normally, a sequence of events can only be intercepted && consumed by one View. In special cases, you can force it to other views.

  3. An event sequence, once intercepted by a View, can only be handled by the View, and onInterceptTouchEvent will not be called again, that is, no longer unnecessary to ask whether to intercept.

  4. [onTouchEvent()] returns false if the initial ACTION_DOWN event is not consumed when the View starts processing events. Subsequent events from this event sequence are then handed over to the View, and events are redirected up to the parent View’s onTouchEvent().

  5. If the View consumes only the ACTION_DOWN event and no other touch events, the event will disappear. And the onTouchEvent() of the parent View is not called; These events will eventually be handled by the Activity

  6. There is no onInterceptTouchEvent() method in the View, the event is sent to the View, and the onTouchEvent() is called. Activity does not have onInterceptTouchEvent()

  7. The ViewGroup provides an additional onInterceptTouchEvent(), which returns false by default without intercepting any events

  8. OnTouchEvent () default consumption event return true; In special cases return false: The View is set to clickable = = false && longClickable = = false. “Button default clickable = = true,TextView default clickable = = false”

  9. The value of the enable property of the View, Does not affect the onTouchEvent () the default return value of true, clickable = = true | | longClickable = = true – > onTouchEvent () will return true by default;

  10. If enable = = false, onTouchListener.ontouch () will not be executed

  11. RequestDisallowInterceptTouchEvent () can intervention in a child View of all the parent View 】 【 event distribution

5. Code testing & verification

The log result of the previous normal [click event] event distribution + processing

5.1 train of thought

  1. Override the “dispatchTouchEvent” and “onTouchEvent” methods, and add the corresponding log to the node
  2. You can override the three methods of “dispatchTouchEvent” (” onInterceptTouchEvent “) and “onTouchEvent” (” onTouchEvent “) by customisingViewGroupBBB
  3. 2. Customize ViewGroupAAA
  4. Override the “dispatchTouchEvent” and “onTouchEvent” methods in the Activity, and add the corresponding log log to the node
  5. The activity of the layout file put controls, contain ViewGroupAAA ViewGroupBBB, ViewGroupBBB contains ViewTestCCC
  6. In the activity, get ViewTestCCC, set setOnTouchListener, setOnClickListener, and add a log to the callback method
  7. Modify the return value of the key node method to gain insight into the event distribution & processing mechanism

5.2 Code first

ViewTestCCC.java

public class ViewTestCCC extends View {
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e("touch_test"."===== ViewTestCCC.dispatchTouchEvent ====");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("touch_test"."===== ViewTestCCC.onTouchEvent ====");
        return super.onTouchEvent(event);
    }
    public ViewTestCCC(Context context) {
        super(context);
    }
    public ViewTestCCC(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    public ViewTestCCC(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    public ViewTestCCC(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes); }}Copy the code

ViewGroupBBB.java

public  class ViewGroupBBB extends RelativeLayout {
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("touch_test"."===== ViewGroupBBB.dispatchTouchEvent ====");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("touch_test"."===== ViewGroupBBB.onInterceptTouchEvent ====");
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("touch_test"."===== ViewGroupBBB.onTouchEvent ====");
        return super.onTouchEvent(event);
    }
    public ViewGroupBBB(Context context) {
        super(context);
    }
    public ViewGroupBBB(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public ViewGroupBBB(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    public ViewGroupBBB(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes); }}Copy the code

ViewGroupAAA.java

public  class ViewGroupAAA extends RelativeLayout {
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("touch_test"."===== ViewGroupAAA.dispatchTouchEvent ====");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("touch_test"."===== ViewGroupAAA.onInterceptTouchEvent ====");
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("touch_test"."===== ViewGroupAAA.onTouchEvent ====");
        return super.onTouchEvent(event);
    }
    public ViewGroupAAA(Context context) {
        super(context);
    }
    public ViewGroupAAA(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public ViewGroupAAA(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    public ViewGroupAAA(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes); }}Copy the code

The Activity layout file.xml


      
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".BaseSuperResourceActivity">

    <com.cupster.base_super_resource.ViewGroupAAA
        android:layout_width="500dp"
        android:layout_height="500dp"
        android:background="@android:color/holo_red_light"

        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        >

        <com.cupster.base_super_resource.ViewGroupBBB
            android:layout_centerInParent="true"
            android:layout_width="300dp"
            android:layout_height="300dp"
            android:background="@android:color/holo_green_light"
            >
            <com.cupster.base_super_resource.ViewTestCCC
                android:id="@+id/view_ccc"
                android:layout_centerInParent="true"
                android:background="@android:color/holo_orange_light"
                android:layout_width="150dp"
                android:layout_height="150dp"
                />
        </com.cupster.base_super_resource.ViewGroupBBB>

    </com.cupster.base_super_resource.ViewGroupAAA>
</androidx.constraintlayout.widget.ConstraintLayout>
Copy the code

activity


public class BaseSuperResourceActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_base_super_resource);

        View viewCCC = findViewById(R.id.view_ccc);
        viewCCC.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                Log.e("touch_test"."===== ViewTestCCC.[[OnTouchListener]].onTouch() ====");
                return false; }}); viewCCC.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.e("touch_test"."===== ViewTestCCC.<<OnClickListener>>.onClick() ===="); }}); }@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("touch_test"."===== Activity.dispatchTouchEvent ====");
        return super.dispatchTouchEvent(ev);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("touch_test"."===== Activity.onTouchEvent ====");
        return super.onTouchEvent(event); }}Copy the code

5.3 Modifying the return value for test verification

Node logs of normal click events







 viewCCC.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                Log.e("touch_test"."===== ViewTestCCC.[[OnTouchListener]].onTouch() ====");
                return true;// Consume the event, and the distribution process will not continue}});Copy the code

Result: onTouchEvent() is no longer called, and OnTouchListener has a higher priority than onTouchEvent()





2. Change the return value of [onTouchEvent()] in viewTestccc.java to false: no processing

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("touch_test"."===== ViewTestCCC.onTouchEvent ====");
// return super.onTouchEvent(event);
        return false;
    }
Copy the code

Results: ViewGroupBBB () and ViewGroupAAA () return super.onTouchEvent() directly, so when the View’s onTouchEvent() is not processed, The event is progressively sent back to the parent view for processing,





3. Modify the onInterceptTouchEvent in viewGroupbbb. Java

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("touch_test"."===== ViewGroupBBB.onInterceptTouchEvent ====");
        return true;
    }
Copy the code

Result: if it intercepts the event, it calls itself [onTouchEvent()] to handle the event





4. [onTouchEvent()] returns true: it consumes the event itself, so it no longer sends back to the parent view

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("touch_test"."===== ViewGroupBBB.onInterceptTouchEvent ====");
// return super.onInterceptTouchEvent(ev);
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("touch_test"."===== ViewGroupBBB.onTouchEvent ====");
// return super.onTouchEvent(event);
        return true;
    }
Copy the code

Results:





6. So far, the View of the event distribution & processing, has reached a complete understanding, more in-depth welcome to follow the source analysis article.