Android Touch Event Distribution deep understanding of _android

Source: Internet
Author: User
Tags gety touch

This article with you in-depth learning touch event distribution, the specific contents are as follows
1. Touch action and event sequence

(1) The action of touching the event

Touch action A total of three kinds: Action_down, Action_move, action_up. When the user's finger touches the screen, it produces an action for the action_down of the touch event, at this point if the user's finger immediately left the screen, will produce an action for the ACTION_UP touch event, if the user finger contact screen after continuing to slide, when the sliding distance exceeds the system predefined distance constants, Generates a touch event that is Action_move, and the predefined distance constants used in the system to determine whether a user's finger is sliding on the screen is a action_move action, which is called Touchslop, through Viewconfiguration.get ( GetContext ()). Getscaledtouchslop () obtained.

(2) Sequence of events

When the user's finger touches the screen, slides on the screen, and leaves the screen, the process produces a series of touch events:action_down--> several action_move-->action_up. This series of touch events is a sequence of events.

2. The distribution of touch events

(1) Overview

When a touch time is generated, the system is responsible for handling the touch event to a view (TargetView), and the process of touching events passing to the TargetView is the distribution of the touches event.

The distribution order of the touch events:activity--> the view--> of the top-level view--> top-level view ...-->target view

Response order of the touch events: TargetView--> targetview parent container--> ...--> top view-->activity

(2) The specific process of Toush event distribution

A. Activity's distribution of touch events

When the user's finger touches the screen, a touch event is generated, and the motionevent that encapsulates the touching event is first passed to the current Activity,activity Dispatchtouchevent method to distribute the touchscreen event. The actual work of distributing touch events is done by the window of the current activity, and window passes the touch event to Decorview (the current user interface top-level view). The Dispatchtouchevent method code for the activity is as follows:

public boolean dispatchtouchevent (motionevent ev) {
  if (ev.getaction () = = Motionevent.action_down) {
    Onuserinteraction ();
  }
  if (GetWindow (). superdispatchtouchevent (EV)) {return
    true;
  }
  return ontouchevent (EV);
}

As you can see from the above code, the touch event is distributed to Window superdispatchtouchevent, if this method returns true, meaning that the distribution of the touch event ends and the return false indicates that it is distributed through layers. No Child view handles this event, that is, the Ontouchevent method for all child view returns False (that is, the touch event is not "consumed"). The Ontouchevent method of the activity is invoked to handle this touch event.

In the window's Superdispatchtouchevent method, the touch event is first distributed to Decorview because it is the top-level view of the current user interface. The Superdispatchtouchevent method for Windows is as follows:

Public abstract Boolean superdispatchtouchevent (Motionevent ev);
is an abstract method that is implemented by the implementation class of Window Phonewindow, and the code for the Phonewindow Superdispatchtouchevent method is as follows:

public boolean superdispatchtouchevent (Motionevent ev) {return
  mdecor.superdispatchtouchevent (event);
}

As the above code is available, Phonewindow's Superdispatchtouchevent method actually accomplishes its work by Decorview Superdispatchtouchevent method, that is to say, The window of the current activity passes this touch event directly to Decorview. In other words, the current touch event has been distributed as follows: Activity-->window-->decorview.

B. Top view distribution of touch events

After the activity and window distribution, the touch event has now been passed to the Decorview dispatchtouchevent method. Decorview is essentially a viewgroup (more specifically framelayout), the work done by the Dispatchtouchevent method of ViewGroup can be divided into the following stages, the main code for the first phase is as follows:

Handle an initial down.
if (actionmasked = = Motionevent.action_down) {
  //throw away all previous ' when starting a the new touch gesture.
  The framework may have dropped the "Up" or "Cancel event for" the previous gesture due to a app switch, ANR, or some other State change.
  Cancelandcleartouchtargets (EV);
  Resettouchstate ();
}

The first phase of the main work of the two: one is in the 6th line of the Resettouchstate method to complete the flag_disallow_intercept tag reset Second, the Cancelandcleartouchtargets method on line 5th clears the current motionevent's touch target. A description of the flag_disallow_intercept tag and touch target is provided below.

The second phase of the main task is to determine whether the current viewgroup to intercept this touch event, the main code is as follows:

Check for interception.
Final Boolean intercepted;
if (actionmasked = = MOTIONEVENT.ACTION_DOWM | | | mfirsttouchtarget!= NULL) {
  final Boolean disallowintercept = (MGROUPF Lags & Flag_disallow_intercept)!= 0;
  if (!disallowintercept) {
    intercepted = onintercepttouchevent (EV);
    Ev.setaction (action); Restore action in case it is changed
  } else {
    intercepted = false;
  }
} else {
  //there are no Touc The H targets and this action are not a initial down so this view group continues to intercept touches.
  Intercept =true;
}

As we can see from the above code, when a touch event is passed to the ViewGroup, the first thing to determine whether the action is Action_down, if this event is Action_ Down or mfirsttouchtarget is not NULL, it will be based on the flag_disallow_intercept tag to determine whether to intercept this touch event. So what is Mfirsttouchtarget? When the touch event is successfully processed by ViewGroup's child view, the Mfirsttouchtarget is assigned to the view that successfully handles the touch event, which is the improved touch target.

Summarize the process of the above code: if the child view does not interfere with ViewGroup interception (disallowintercept in the above code is false), if the current event is Action_down or mfirsttouchtarget is not empty, The ViewGroup Onintercepttouchevent method is invoked to determine whether the event is eventually blocked, otherwise (there is no TargetView and this event is not action_down), the current ViewGroup intercepts the event. Once ViewGroup intercepts a touch event, the mfirsttouchtarget is not assigned, so when Action_move or action_up is passed to the ViewGroup, the mtouchtarget is null , so the condition on line 3rd of the above code will be intercepted by False,viewgroup. The conclusion is that once ViewGroup intercepts an event, the remaining events in the same sequence of events will also be blocked by default and will not be asked for interception (that is, onintercepttouchevent will not be called again).

There is a special case where the child view sets the parent container's flag_disallow_intercept to true through the Requestdisallowintercepttouchevent method, which indicates whether the parent container is not allowed to intercept. True to indicate that it is not allowed. Doing so will prevent the parent container from intercepting all touch events except Action_down. The reason that the Action_down event cannot be intercepted is because whenever the Action_down event arrives, the flag_disallow_intercept is reset to the default value (FALSE). So whenever you start a new touch event sequence (that is, a action_down action arrives), you will be asked ViewGroup whether to intercept the event by calling Onintercepttoucheven. When the Action_down event arrives, resetting the tag bit is done in the first stage above.

Next, you will enter the third phase of the work:

Final Boolean canceled = Resetcancelnextupflag (this) | |
actionmasked = = Motionevent.action_cancel;
Final Boolean split = (Mgroupflags & flag_split_motion_events)!= 0;
Touchtarget newtouchtarget = null;
Boolean alreadydispatchedtonewtouchtarget = false; if (!canceled &&!intercepted) {//Is not action_cancel and does not intercept if (actionmasked = = Motionevent.action_down) {/ /If the current event is action_down to find this event the new touch target final int actionindex = Ev.getactionindex ();
     Always 0 for down ... final int childrencount = Mchildrencount; if (Newtouchtarget = = null && childrencount!= 0) {//searching for the touch target to receive this event based on the coordinates of the contact final float x
       = Ev.getx (Actionindex);

       Final float y = ev.gety (Actionindex);
       Final view[] children = Mchildren;
         Iterate over all child view for (int i = childrenCount-1 i >= 0; i--) {final int childindex = i;
         Final View child = Children[childindex];
 Look for the child view that can receive this event and touch the event coordinates within its region        if (!canviewreceivepointerevents (child) | |!istransformedtouchpointinview (x, y, child, null)) {Continu
         E } Newtouchtarget = Gettouchtarget (child); A qualifying view was found, assigned to Newtouchtarget if (newtouchtarget!= null) {//child is already receiving touch WI
           Thin its bounds.
           Give it the new pointer in addition to ones it is handling.
           Newtouchtarget.pointeridbits |= idbitstoassign;
         Break
         } resetcancelnextupflag (child); Pass the Action_down event to the subassembly for processing if (Dispatchtransformedtouchevent (EV, FALSE, Child, Idbitstoassign)) {//c
           Hild wants to receive the within its bounds.
           Mlasttouchdowntime = Ev.getdowntime (); if (preorderedlist!= null) {//childindex points into the presorted list, find original index for ( int j=0;j<childrencount;j++) {if (Children[childindex]==mchildren[j]) {MLASTTOuchdownindex=j;
               Break
           }} else {mlasttouchdownindex = Childindex;
           } Mlasttouchdownx = Ev.getx ();
           Mlasttouchdowny = Ev.gety (); Assigning Mfirsttouchtarget to Newtouchtarget, this view becomes the starting point for the new touch event Newtouchtarget = Addtouchtarget (Child, Idbitstoassig
           n);
           Alreadydispatchedtonewtouchtarget = true;
         Break
 }           
       }
     }
  }
}

When ViewGroup does not intercept this event, the touch event is distributed to its child view for processing, with the code starting at line 21st: traversing all ViewGroup's child views, looking for a child view that can handle this touch event. If a child view does not play an animation and the touch event coordinates are in its area, the child view can handle the touch event and assign the child view to Newtouchtarget.

If the currently traversed child view can handle this touch event, it enters the Dispatchtransformedtouchevent method on line 38th, which actually invokes the Dispatchtouchevent method of the child view. The relevant code in the Dispatchtransformedtouchevent method is as follows:

if (child = = null) {
  handled = Super.dispatchtouchevent (event);
} else {
  handled = Child.dispatchtouchevent ( event);
}

If the Dispatchtransformedtouchevent method passes in a child parameter that is not NULL, it invokes the Dispatchtouchevent method of the children (that is, the view that handles the touch event). If the Dispatchtouchevent method of the child view returns True, the Dispatchtransformedtouchevent method also returns True, indicating that a hit target was successfully found to handle the event. The Newtouchtarget is assigned to Mfirsttouchtarget on line 55th (this assignment is done within the Addtouchtarget method) and jumps out of the loop of the child view traversal. If the Dispatchtouchevent method of the child view returns False,viewgroup, the event is distributed to the next child view.

If all the child view is traversed, the touch event is not processed (the ViewGroup does not have a child view or all of the child view's dispatchtouchevent return false), and ViewGroup handles the touch event on its own, with the relevant code as follows:

 if (Mfirsttouchtarget = = null) {
   handled = dispatchtransformedtouchevent (EV, canceled, NULL, Touchtarget.all_ pointer_ids);
 }

As you can know from the above code, the Dispatchtransformedtouchevent method is invoked when ViewGroup handles the touch event itself, and the passed child parameter is null. According to the analysis above, when the incoming chid is null, the Super.dispatchtouchevent method is invoked, that is, the Dispatchtouchevent method of the view class is invoked.

C. View's handling of touch events

The main code for the Dispatchtouchevent method of view is as follows:

public boolean dispatchtouchevent (Motionevent event) {
  Boolean result = false;
  . . .
  
  if (onfiltertoucheventforsecurity (event)) {
    //noinspection simplifiableifstatement
    listenerinfo li = Mlistenerinfo;
    if (Li!= null && li.montouchlistener!= null && (Mviewflags & enabled_mask) = = ENABLED
        && Li.mOnTouchListener.onTouch (this, event)) {result
      = true;
    }
    
    if (!result && ontouchevent (event) {result
      = true;
    }
    . . .
    return result;
}

As you can tell from the code above, the view handles the touch event as follows: Because view does not contain child elements, it handles events itself. It first determines whether the Ontouchlistener is set, and if it is set, the Ontouch method is invoked, and if the Ontouch method returns True (indicating that the touch event has been consumed), the Ontouchevent method is not called again If the Ontouch method returns false or does not have a ontouchlistener set, the Ontouchevent method is invoked, and the relevant code that ontouchevent the specific handling of the touch event is as follows:

if ((viewflags & clickable) = = Clickable | |
      (ViewFlags & long_clickable) = = long_clickable)) {switch (event.getaction ()) {case MOTIONEVENT.ACTION_UP:
      Boolean prepressed = (Mprivateflags & pflag_prepressed)!= 0;
          if ((Mprivateflags & pflag_pressed)!= 0 | | prepressed) {... if (!mhasperformedlongpress) {
          
          This is a tap, so remove the Longpress check Removelongpresscallback (); Only perform take click Actions if we were the pressed state if (!focustaken) {//use a runnabl
            E and post this rather than calling PerformClick directly.
            This lets is the visual state of the view update before click Actions Start.
            if (Mperformclick = = null) {Mperformclck = new Peformclick ();
            } if (!post (Mperformclick)) {PerformClick ();
      }
          }
        }
        . . .
      }
  Break }
  ..
  .
return true; }


As you can know from the above code, the Long_clickable property defaults to false as long as the clickable and long_clickable properties of the view are true (the clickable property of the view and the specific view. Setoncliklistener and Setonlongclicklistener automatically set the above two properties to true respectively, then this view consumes the touch event, even if the view is in a disabled state. If the current event is action_up, the PerformClick method is also called, and if the view is set Onclicklistener, the PerformClick method invokes the OnClick method inside it. The PerformClick method code is as follows:

public boolean PerformClick () {
  final boolean result;
  Final Listenerinfo li = mlistenerinfo;
  if (Li!= null && li.monclicklistener!= null) {
    playsoundeffect (soundeffectconstants.click);
    Li.mOnClickListener.onClick (this);
    result = true;
  } else {result
    = false;
  }
  Sendaccessibilityevent (accessibilityevent.type_view_clicked);
  return result;
}


The above is a simple summary of my learning about touch events in Android, and it's not clear enough to describe in many places.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.