Body ### talk about UI event passing

What are UI events?

  • The moment you touch a UI control on the screen, the event occurs
  • The MotionEvent object contains all touch events, such asThe position of touch, multi-finger touch, etc
  • MotionEvent describes the current operation type. The following are common types (numbers represent values) :
  • ACTION_DOWN = 0Press the
  • ACTION_UP = 1Lift up
  • ACTION_MOVE = 2mobile
  • ACTION_CANCEL = 3The action to cancel
  • ACTION_OUTSIDE = 4Action out of bounds
  • ACTION_POINTER_DOWN = 5If one point is already held down, press another point
  • ACTION_POINTER_UP = 6When multiple points are held down, the last point not released is called

How are events delivered?

The above diagram is abbreviated as follows:

We thought that the event was passed from the child layout to the parent, because intuitively we first encountered that the child layout got the wrong order of events: view1 –> ViewGroup2 –> ViewGroup1

√ It turns out that the event is passed from the parent layout to the child layout. The parent layout decides where to click and then passes the event to the child layout. If an event delivered to a child layout is not intercepted and consumed, the event is delivered to the parent layout. Correct sequence of events that are not blocked or consumed: Activity –> ViewGroup1 –> ViewGroup2 –> ViewGroup2 –> ViewGroup1 –> Activity

The following Log is a series of events that occur when a finger clicks, slides, and lifts view1 (0. Press; 1. Lift; 2. Move) :Copy the code
    E/MainActivity: ----------- dispatchTouchEvent = 0
    E/ViewGroup1: ------------- dispatchTouchEvent = 0
    E/ViewGroup1: ------------- onInterceptTouchEvent = 0
    E/ViewGroup2: ------------- dispatchTouchEvent = 0
    E/ViewGroup2: ------------- onInterceptTouchEvent = 0
    E/View1: ------------------ dispatchTouchEvent = 0
    E/View1: ------------------ onTouchEvent = 0
    E/ViewGroup2: ------------- onTouchEvent = 0
    E/ViewGroup1: ------------- onTouchEvent = 0
    E/MainActivity: ----------- onTouchEvent = 0
    E/MainActivity: ----------- dispatchTouchEvent = 2
    E/MainActivity: ----------- onTouchEvent = 2
    E/MainActivity: ----------- dispatchTouchEvent = 2
    E/MainActivity: ----------- onTouchEvent = 2
    E/MainActivity: ----------- dispatchTouchEvent = 2
    E/MainActivity: ----------- onTouchEvent = 2
    E/MainActivity: ----------- dispatchTouchEvent = 1
    E/MainActivity: ----------- onTouchEvent = 1
    E/MainActivity: ----------- dispatchTouchEvent = 1
    E/MainActivity: ----------- onTouchEvent = 1
Copy the code
To observe the
You can see that events are passed from the outer layout to the inner sub-layout, In the output from the child layout (Activity --> ViewGroup1 --> ViewGroup2 --> ViewGroup2 --> ViewGroup1 --> Activity)
The log also shows that when pressed events are not intercepted, all state events are handled by the Activity

How to intercept?

  • Events are intercepted with dispatchTouchEvent when the return value is true

  • Now take ViewGroup1 as an example: let dispatchTouchEvent in ViewGroup1 return true for the sequence of events that occur when a finger clicks, moves, or lifts on View1 (0). Press; 1. Lift; 2. Mobile)

    Copy the code

E/MainActivity: —————- dispatchTouchEvent = 0 E/ViewGroup1: —————— dispatchTouchEvent = 0 E/MainActivity: —————- dispatchTouchEvent = 2 E/ViewGroup1: —————— dispatchTouchEvent = 2 E/MainActivity: —————- dispatchTouchEvent = 2 E/ViewGroup1: —————— dispatchTouchEvent = 2 E/MainActivity: —————- dispatchTouchEvent = 2 E/ViewGroup1: —————— dispatchTouchEvent = 2 E/MainActivity: —————- dispatchTouchEvent = 1 E/ViewGroup1: —————— dispatchTouchEvent = 1 “`

To observe the
You can see that the event passed to ViewGroup1 is intercepted and not consumed by any layout
That is, if the event is intercepted before it has been consumed, the touch will be invalid
We can use dispatchTouchEvent to determine which events need to be intercepted and which events don't need to be intercepted.

How do I get it?

  • Get events from onInterceptTouchEvent, when the return value is true

  • The onTouchEvent method is called when we get the event. After calling this method, if we set OnTouchListener, the touch listener will be called. Let’s take ViewGroup2 as an example: Let the onInterceptTouchEvent in ViewGroup2 return true for events that occur when a finger clicks, moves, or lifts from View1. Press; 1. Lift; 2. Mobile)

E/MainActivity: ----------------  dispatchTouchEvent = 0
E/ViewGroup1: ------------------  dispatchTouchEvent = 0
E/ViewGroup1: ------------------  onInterceptTouchEvent = 0
E/ViewGroup2: ------------------  dispatchTouchEvent = 0
E/ViewGroup2: ------------------  onInterceptTouchEvent = 0
E/ViewGroup2: ------------------  onTouchEvent = 0
E/ViewGroup1: ------------------  onTouchEvent = 0
E/MainActivity: ----------------  onTouchEvent = 0
E/MainActivity: ----------------  dispatchTouchEvent = 2
E/MainActivity: ----------------  onTouchEvent = 2
E/MainActivity: ----------------  dispatchTouchEvent = 2
E/MainActivity: ----------------  onTouchEvent = 2
E/MainActivity: ----------------  dispatchTouchEvent = 2
E/MainActivity: ----------------  onTouchEvent = 2
E/MainActivity: ----------------  dispatchTouchEvent = 1
E/MainActivity: ----------------  onTouchEvent = 1
Copy the code
observation why To solve
Oh my! Why did MainActivity eat events that move and lift fingers after I got the event? Angry!!!!! OnTouchEvent does not return true if it handles the DOWN event. If onTouchEvent returns false when it handles DOWN, no consumption event will be consumed, the event will be returned to the parent layout, and no subsequent events will be passed. The onTouchEvent method returns true when judged to be a DOWN event, the consumption described below

How to spend?

  • As mentioned above, there is a problem left over from obtaining the event: after obtaining the press event, why not continue to obtain the subsequent event? OnTouchEvent does not return true when pressed, causing the event to revert back to the parent layout, i.e., no consumption event.

    OnInterceptTouchEvent returns true from ViewGroup2. Add a judgment to the onTouchEvent method if (event.getAction() == motionEvent.action_down) {return true; } a series of events that occur when a finger clicks, moves, or lifts View1 (0). Press; 1. Lift; 2. Mobile)Copy the code
    Copy the code

E/MainActivity: —————- dispatchTouchEvent = 0 E/ViewGroup1: —————— dispatchTouchEvent = 0 E/ViewGroup1: —————— onInterceptTouchEvent = 0 E/ViewGroup2: —————— dispatchTouchEvent = 0 E/ViewGroup2: —————— onInterceptTouchEvent = 0 E/ViewGroup2: —————— onTouchEvent = 0 E/MainActivity: —————- dispatchTouchEvent = 2 E/ViewGroup1: —————— dispatchTouchEvent = 2 E/ViewGroup1: —————— onInterceptTouchEvent = 2 E/ViewGroup2: —————— dispatchTouchEvent = 2 E/ViewGroup2: —————— onTouchEvent = 2 E/MainActivity: —————- onTouchEvent = 2 E/MainActivity: —————- dispatchTouchEvent = 2 E/ViewGroup1: —————— dispatchTouchEvent = 2 E/ViewGroup1: —————— onInterceptTouchEvent = 2 E/ViewGroup2: —————— dispatchTouchEvent = 2 E/ViewGroup2: —————— onTouchEvent = 2 E/MainActivity: —————- onTouchEvent = 2 E/MainActivity: —————- dispatchTouchEvent = 1 E/ViewGroup1: —————— dispatchTouchEvent = 1 E/ViewGroup1: —————— onInterceptTouchEvent = 1 E/ViewGroup2: —————— dispatchTouchEvent = 1 E/ViewGroup2: —————— onTouchEvent = 1 E/MainActivity: —————- onTouchEvent = 1

| ` observation ` | | - | | ` from abovelogAs you can see, the onTouchEvent press event in ViewGroup2 now returns onetrue, press the events has not been passed back to the parent layout, the subsequent events will get ` | | ` can be seen that when passed subsequent events, has not called again ViewGroup2 onInterceptTouchEvent method ` | | ` we just return of events that will press DOWNtrue, so any activity that moves or lifts can also be retrieved in addition to the pressed event. When onTouchEvent returns one regardless of three seven onetrueWhen the activity will not get to the event ` |! [when consuming ViewGroup2 press DOWN event. PNG](http://upload-images.jianshu.io/upload_images/1552955-078ecc8bed94af8d.png? imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ! OnTouchEvent is returned directly in ViewGroup2true. PNG] (HTTP: / / http://upload-images.jianshu.io/upload_images/1552955-fe80728c817d87c0.png? imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)How about ### Button fetch event?- Now change View1 to Button1, and the rest to the original state. Let's look at touchlog
Copy the code

E/MainActivity: ————- dispatchTouchEvent = 0 E/ViewGroup1: ————— dispatchTouchEvent = 0 E/ViewGroup1: ————— onInterceptTouchEvent = 0 E/ViewGroup2: ————— dispatchTouchEvent = 0 E/ViewGroup2: ————— onInterceptTouchEvent = 0 E/Button1: —————— dispatchTouchEvent = 0 E/Button1: —————— onTouchEvent = 0 E/MainActivity: ————- dispatchTouchEvent = 2 E/ViewGroup1: ————— dispatchTouchEvent = 2 E/ViewGroup1: ————— onInterceptTouchEvent = 2 E/ViewGroup2: ————— dispatchTouchEvent = 2 E/ViewGroup2: ————— onInterceptTouchEvent = 2 E/Button1: —————— dispatchTouchEvent = 2 E/Button1: —————— onTouchEvent = 2 E/MainActivity: ————- dispatchTouchEvent = 2 E/ViewGroup1: ————— dispatchTouchEvent = 2 E/ViewGroup1: ————— onInterceptTouchEvent = 2 E/ViewGroup2: ————— dispatchTouchEvent = 2 E/ViewGroup2: ————— onInterceptTouchEvent = 2 E/Button1: —————— dispatchTouchEvent = 2 E/Button1: —————— onTouchEvent = 2 E/MainActivity: ————- dispatchTouchEvent = 1 E/ViewGroup1: ————— dispatchTouchEvent = 1 E/ViewGroup1: ————— onInterceptTouchEvent = 1 E/ViewGroup2: ————— dispatchTouchEvent = 1 E/ViewGroup2: ————— onInterceptTouchEvent = 1 E/Button1: —————— dispatchTouchEvent = 1 E/Button1: —————— onTouchEvent = 1

- Check out the sequence diagram! [Button gets the touch event.png](http://upload-images.jianshu.io/upload_images/1552955-737a88ead364d2df.png? ImageMogr2 /auto-orient/strip% 7CImageView2/2 /w/1240) - This is not the same as the image above 'when the onTouchEvent is returned directly in ViewGroup2trueIs the effect the same? That is, Button acquires events by default and does not return them to the main layout. - Wait, there's another one!! You all know that layout has a clickable property. When setting its value totrueMake the layout event as button says! - [Android event distribution mechanism is fully resolved, Take you thoroughly understanding from the perspective of source (on)] (http://blog.csdn.net/guolin_blog/article/details/9097463) - [Android event dispatch mechanism completely, Take you thoroughly understand (down) from the perspective of source] (http://blog.csdn.net/guolin_blog/article/details/9153747)### Practical application- A simple application of XML layoutCopy the code

The activity codeCopy the code

package com.examples.customtouch;

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

/ * *

  • Created by Dave Smith

  • Double Encore, Inc.

  • Date: 9/25/12

  • TouchListenerActivity */ public class TouchListenerActivity extends Activity implements View.OnTouchListener {

    /* Views to display last seen touch event */ CheckBox mLockBox;

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

     mLockBox = (CheckBox) findViewById(R.id.checkbox_lock);
    
     findViewById(R.id.selection_first).setOnTouchListener(this);
     findViewById(R.id.selection_second).setOnTouchListener(this);
     findViewById(R.id.selection_third).setOnTouchListener(this);
    Copy the code

    }

    @Override public boolean onTouch(View v, MotionEvent event) { /* * Consume the events here so the buttons cannot process them * if the CheckBox in the UI is checked */ Log.e(“TouchListenerActivity”, getNameForEvent(event)); return mLockBox.isChecked(); }

    @Override public boolean onTouchEvent(MotionEvent event) { Log.e(“onTouchEvent”, getNameForEvent(event)); return super.onTouchEvent(event); }

    private String getNameForEvent(MotionEvent event) { String action = “”; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: action = “ACTION_DOWN”; break; case MotionEvent.ACTION_CANCEL: action = “ACTION_CANCEL”; break; case MotionEvent.ACTION_MOVE: action = “ACTION_MOVE”; break; case MotionEvent.ACTION_UP: action = “ACTION_UP”; break; default: return null; }

     return String.format("%s\n%.1f, %.1f", action, event.getX(), event.getY());
    Copy the code

    }}

! [Effect](http://upload-images.jianshu.io/upload_images/1552955-c3f471a317844513.png? ImageMogr2 / auto - received/strip % 7 cimageview2/2 / w / 1240) | ` state ` | ` describe ` | | : - : | : - : | | ` when the Lock Selection did not check the ` | radio can normal Selection at the bottom of the ` ` | | ` when the Lock Selection when checked ` | radio can't click at the bottom of the ` ` | - everyone is wondering, why the check box selected, the ontouch returnedtrueI can't click on it anymore. Why not returnfalseUnable to click, returntrueWhen to click? In fact, these controls can be clicked by default are the default to get events, such as the above said button why get events, so returntrueandfalseContrary to expectations.# Knowledge and materials used1. The Android studio plugin plantUml draw the sequence diagram and class diagram 2. [plantUml quick guide] (HTTP: / / http://archive.3zso.com/archives/plantuml-quickstart.html# the SEC - 5-3) and [PlantUML website] (http://plantuml.com/classes.html)3. [Android event dispatch mechanism fully, take you thoroughly understanding from the perspective of source code (on)] (http://blog.csdn.net/guolin_blog/article/details/9097463) [Android event dispatch mechanism completely, Take you thoroughly understand (down) from the perspective of source] (http://blog.csdn.net/guolin_blog/article/details/9153747) 4. [public technology point of View Events] (HTTP: / / http://a.codekk.com/detail/Android/Trinea/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8B%20View%20%E4%BA%8 E4 B % % BB E9 A0 BC E4 B6% % % % % % 80% 92) 5. The example from here] [last (https://github.com/devunwired/custom-touch-examples)Copy the code