Android takes you through event distribution

Keywords: PHP Android xml

It has been a while since we worked. It is necessary to understand the mechanism of event transmission. Recently, we studied it and recorded our experience.
1 Events in Android
There are many touch events in android. In the MotionEvent class of encapsulation, clicking, touching and sliding are our common events.

  • MotionEvent.ACTION_DOWN
  • MotionEvent.ACTION_MOVE
  • MotionEvent.ACTION_UP
  • MotionEvent.ACTION_CANCEL

2 Core Approach
Before we can understand the delivery mechanism, we need to learn a few ways.
2.1ViewGroup

  • dispatchTouchEvent distributes events, accepts them by default and distributes them downward.If true is returned, events are intercepted and not distributed.The same below.
  • The onInterceptTouchEvent preprocessing event returns false by default and true for interception
  • OnTouchEvent handles events and returns false by default, without consuming events.If clickable=true is set in the root layout or code, super.onTouchEvent returns true, indicating that events were consumed.

2.2View

  • dispatchTouchEvent
  • onTouchEvent handles event return values by looking at the view property clickable==true

onTouchEvent return value for 2.3View/ViewGroup:

  • super.onTouchEvent returns true if view/viewGroup is clickable, such as Button, clickable = true
  • If view/viewGroup is not clickable, such as TextView, clickable = false, super.onTouchEvent returns false
  • Setting the view/viewGroup clickable property to true in xml returns true for view:super.onTouchEvent

2.4 Core

  • clickable affects the return value of super.onTouchEvent
  • If false is returned, View can only handle down events, and subsequent events will not be triggered
  • If true is returned, the view down\move\up can be triggered

3 Event Delivery
A complete screen touch event: finger press, slide, lift.This event consists of one action_down, several actions_moves, and one action_up.So how does it get across in our screens?
By default, event delivery is a process from Activity to ViewGroup to View, which is ultimately accepted by View.Figure:

  

We define a MyViewGroup and a MyView, and how to print them.
MyViewGroup, clickable false, super.onTouchEvent defaults to false, do not consume events

public class MyViewGroup extends FrameLayout {

    String Tag = "===MyViewGroup";

    public MyViewGroup(Context context) {
        super(context);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.e(Tag,"dispatchTouchEvent ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e(Tag,"dispatchTouchEvent ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.e(Tag,"dispatchTouchEvent ACTION_UP");
                break;
        }
        return super.dispatchTouchEvent(ev);
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.e(Tag, "onInterceptTouchEvent ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e(Tag, "onInterceptTouchEvent ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.e(Tag, "onInterceptTouchEvent ACTION_UP");
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }


    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.e(Tag, "onTouchEvent ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e(Tag, "onTouchEvent ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.e(Tag, "onTouchEvent ACTION_UP");
                break;
        }
        return super.onTouchEvent(ev);
    }
}

MyView inherits TextView, clickable defaults false, super.onTouchEvent defaults false, and does not consume events

public class MyView extends android.support.v7.widget.AppCompatTextView {

    String Tag = "===MyView";

    public MyView(Context context) {
        super(context);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.e(Tag,"dispatchTouchEvent ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e(Tag,"dispatchTouchEvent ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.e(Tag,"dispatchTouchEvent ACTION_UP");
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.e(Tag,"onTouchEvent ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e(Tag,"onTouchEvent ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.e(Tag,"onTouchEvent ACTION_UP");
                break;
        }
        return super.onTouchEvent(ev);
    }
}

References in the active layout

<com.zcwipe.frecyclerviewdemo.MyViewGroup
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.zcwipe.frecyclerviewdemo.MyView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@color/color_theme"
        android:gravity="center"
        android:text="content" />
</com.zcwipe.frecyclerviewdemo.MyViewGroup>

Events start with action_down,
First activity executes the super.dispatchTouchEvent to distribute to the viewgroup.
Then viewgroup executes super.dispatchTouchEvent, super.onInterceptTouchEvent.
Finally view executes super.dispatchTouchEvent,onTouchEvent.This time the view receives the action_down event in onTouchEvent.

Situation 1:
If the view does not consume an action_down event in the onTouchEvent (false is returned by default, no consumption), the action_down event is handled by the parent layout, which is the onTouchEvent of the viewgroup.If ViewGroup does not handle it.The onTouchEvent handles the action_down event to the upper layout activity.
The action_down event is now delivered.Since neither view nor viewgroup handles the action_down event, the system no longer passes the subsequent event action_move, action_up. log output

Subsequent action_move, action_up events are no longer passed to ViewGroup and View.Processed directly by activity.

Situation 2:
We return true in the action_down event of the view and consume this event (you can also define a button, or set clickable=true, the default consumption event) then the action_down event will not be passed to the viewgroup and the activity, so who will handle the subsequent events?
Action_downs are passed from the upper layer to the view, as are subsequent actions_move and action_up.Since we consume events in the download of the child view, when passing subsequent events, the viewgroup will use the onInterception method to determine if it is necessary to intercept this action_move, action_up action
If not intercepted, onInterception is not handled in the viewgroup, and actions are handled by onTouchEvent in the view:

If intercepted, the action_move of the viewgroup returns true, intercepting the event,

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.e(Tag, "onInterceptTouchEvent ACTION_DOWN");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.e(Tag, "onInterceptTouchEvent ACTION_MOVE");
            return true;
        case MotionEvent.ACTION_UP:
            Log.e(Tag, "onInterceptTouchEvent ACTION_UP");
            break;
    }
    return super.onInterceptTouchEvent(ev);
}

Action is handled by onTouchEvent of viewgroup

 

We have a requirement to accept action_move events in a custom viewgroup to achieve a sliding effect. What should we do?
As we know from scenario 1, if view down does not consume events, and viewgroup does not consume events, then this cannot be achieved.
As we know from scenario 2, if the view consumes the down event and the viewgroup does not intercept it, then it will not be possible.
There are two implementations:
* down consumption in view onTouchEvent, move intercept in view group:onInterceptTouchEvent
* Down does not consume in view onTouchEvent, down consumes in view group:onTouchEvent
Sometimes we don't know if the view consumes events, so use the following scenario to write robust line code, in the viewgroup
1. ontouchevent down consumer events
2. move interception in onInterceptTouchEvent

 @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.e(Tag, "onInterceptTouchEvent ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                return true;
//                break;
            case MotionEvent.ACTION_UP:
                Log.e(Tag, "onInterceptTouchEvent ACTION_UP");
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }


    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.e(Tag, "onTouchEvent ACTION_DOWN");
                return true;
            case MotionEvent.ACTION_MOVE:
                Log.e(Tag, "onTouchEvent ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.e(Tag, "onTouchEvent ACTION_UP");
                break;
        }
        return super.onTouchEvent(ev);
    }

This stabilizes the handling of action_move events in the viewgroup.

Posted by eirikol on Thu, 04 Jul 2019 15:03:02 -0700