Android ViewGroup the event distribution mechanism - source code analysis

To better understand the event distribution mechanism ViewGroup, we have a MyLinerLayout in custom.

public class MyLinearLayout extends LinearLayout
{
    private static final String TAG = MyLinearLayout.class.getSimpleName();
 
    public MyLinearLayout(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }
 
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev)
    {
        int action = ev.getAction();
        switch (action)
        {
        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;
 
        default:
            break;
        }
        return super.dispatchTouchEvent(ev);
    }
 
    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
 
        int action = event.getAction();
 
        switch (action)
        {
        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;
 
        default:
            break;
        }
 
        return super.onTouchEvent(event);
    }
 
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev)
    {
        
        int action = ev.getAction();
        switch (action)
        {
        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 ; 
 
        default :
             BREAK ; 
        } 
        
        return  Super .onInterceptTouchEvent (EV); 
    } 
 
    @Override 
    public  void requestDisallowInterceptTouchEvent ( Boolean disallowIntercept) 
    { 
        Log.e (the TAG, "requestDisallowInterceptTouchEvent" );
         Super .requestDisallowInterceptTouchEvent (disallowIntercept); 
    } 
 
} 
click when Button you can see the print information:

 E/MyLinearLayout(959): dispatchTouchEvent ACTION_DOWN
 E/MyLinearLayout(959): onInterceptTouchEvent ACTION_DOWN
 E/MyButton(959): dispatchTouchEvent ACTION_DOWN
 E/MyButton(959): onTouchEvent ACTION_DOWN
 E/MyButton(959): onTouchEvent ACTION_MOVE
 E/MyLinearLayout(959): dispatchTouchEvent ACTION_MOVE
 E/MyLinearLayout(959): onInterceptTouchEvent ACTION_MOVE
 E/MyButton(959): dispatchTouchEvent ACTION_MOVE
 E/MyButton(959): onTouchEvent ACTION_MOVE
 E/MyLinearLayout(959): dispatchTouchEvent ACTION_UP
 E/MyLinearLayout(959): onInterceptTouchEvent ACTION_UP
 E/MyButton(959): dispatchTouchEvent ACTION_UP
 E/MyButton(959): onTouchEvent ACTION_UP

 
 

You can see the general flow of events is:

 
 

MyLinearLayout的dispatchTouchEvent -> MyLinearLayout的onInterceptTouchEvent -> MyButton的dispatchTouchEvent ->Mybutton的onTouchEvent

As can be seen, the trigger event on the View, the first to capture the event for ViewGroup View is located, and then only to the View itself.

Let's look at dispatchTouchEvent ViewGroup source:

The longer the code, look down at the event:

 public  boolean dispatchTouchEvent (Motion ev) {
         if (! onFilterTouchEventForSecurity (cv)) {
             return  false ; 
        } 
 
        Final  int action = ev.getAction ();
        Final  float xf = ev.getX ();
        Final  float yf = ev.getY ();
        Final  float scrolledXFloat = xf + mScrollX;
        Final  float scrolledYFloat = YF + mScrollY;
        Final Rect frame = mTempRect; 
 
        boolean= disallowIntercept (mGroupFlags & FLAG_DISALLOW_INTERCEPT) = 0! ; 
 
        IF (== Action MotionEvent.ACTION_DOWN) {
             IF (! mMotionTarget = null ) { 
                // put down when the trigger is reset mMotionTarget null 
                mMotionTarget = null ; 
            } 
            // if not allowing interception or not interception but allow intercepted inside will loop through View 
            IF (! disallowIntercept || onInterceptTouchEvent (EV)) {
                 // RESET apos the this Event Action (Just to Protect Ourselves) 
                ev.setAction (MotionEvent.ACTION_DOWN);
                 / / We know we want to dispatch the event down, find a child
                // who can handle it, start with the front-most child.
                final int scrolledXInt = (int) scrolledXFloat;
                final int scrolledYInt = (int) scrolledYFloat;
                final View[] children = mChildren;
                final int count = mChildrenCount;
 
                for (int i = count - 1; i >= 0; i--) {
                    final View child = children[i];
                    if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
                            || child.getAnimation() != null) {
                        child.getHitRect(frame);
                        if (frame.contains(scrolledXInt, scrolledYInt)) {
                            // offset the event to the view's coordinate system
                            final float xc = scrolledXFloat - child.mLeft;
                            final float yc = scrolledYFloat - child.mTop;
                            ev.setLocation(xc, yc);
                            child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
// If you click View to find and return value == true, then mMotionTarget will be assigned to the current sub-View
// and returns true, down the end of the event distribution
IF (child.dispatchTouchEvent (EV)) { // Event the Handled, . A target WE have have now mMotionTarget = Child; return to true ; } // of The Event DID Not the Handled GET, the try The Next View. // the Do Not RESET The Event apos LOCATION, IT apos Not // Necessary here Wallpaper. } } } } }

move source:

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
        final float xf = ev.getX();
        final float yf = ev.getY();
        final float scrolledXFloat = xf + mScrollX;
        final float scrolledYFloat = yf + mScrollY;
        final Rect frame = mTempRect;

        boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;

        //获取down事件时的mMotionTarget
        finalTarget = View mMotionTarget; 

        // allow intercepted and blocked 
        IF (disallowIntercept &&! OnInterceptTouchEvent (EV)) {
            // source placed below speak intercepted 
        } 

        Final  a float XC = scrolledXFloat - ( a float ) target.mLeft; 

        Final  a float YC = scrolledYFloat - ( float ) target.mTop; 
        ev.setLocation (XC, YC); 
        // will not intercept method calls the sub-view distribution of 
        return target.dispatchTouchEvent (EV); 
    } 
By the same token up event, not put up .

1, ACTION_DOWN in, ViewGroup event has been captured, and then determine whether to intercept, if not intercepted, it is found containing the current x, sub View y coordinates assigned to mMotionTarget, then call mMotionTarget.dispatchTouchEvent

2, ACTION_MOVE in, ViewGroup event has been captured, and then determine whether to intercept, if not intercepted, direct call mMotionTarget.dispatchTouchEvent (ev)

3, ACTION_UP in, ViewGroup event has been captured, and then determine whether to intercept, if not intercepted, direct call mMotionTarget.dispatchTouchEvent (ev)

About ViewGroup interception methods:

public  boolean onInterceptTouchEvent (MotionEvent EV) 
    { 
        int Action = ev.getAction ();
         Switch (Action) 
        { 
        Case MotionEvent.ACTION_DOWN:
             // If you feel the need to intercept the 
            return  to true ; 
         Case MotionEvent.ACTION_MOVE:
             // If you feel the need to intercept 
            return  to true ; 
         Case MotionEvent.ACTION_UP:
             // If you feel the need to intercept the 
            return  to true ; 
        } 
        
        return  false ; 
    }

The default is not blocked, that return false; if you want to intercept, just return true on the line, this event would not have to be the child View passed, and if you are true in DOWN retrun,

Then DOWN, MOVE, UP sub-View will not capture the event; if you MOVE return true, then the child will not be captured in View MOVE UP and events

The reason is simple, when onInterceptTouchEvent (ev) return true, the set will mMotionTarget null;

return true if ViewGroup of onInterceptTouchEvent (ev) when ACTION_MOVE, that is intercepted child View of MOVE UP and events;

At this time, still hope to respond to child View MOVE UP and the time we supposed to do?

Android provides us with a method: requestDisallowInterceptTouchEvent (boolean) is used to set whether to allow the interception, so write us directly in the sub-View of dispatchTouchEvent

public boolean dispatchTouchEvent(MotionEvent event)
    {
        getParent().requestDisallowInterceptTouchEvent(true);  
        int action = event.getAction();
 
        switch (action)
        {
        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 ; 
 
        default :
             BREAK ; 
        } 
        return  Super .dispatchTouchEvent (Event); 
    } 
getParent () requestDisallowInterceptTouchEvent (to true);.
Thus, even if the MOVE ViewGroup when return true, the sub-View can capture still and MOVE UP event.
Look ViewGroup the Move Up and interception Source:
if (!disallowIntercept && onInterceptTouchEvent(ev)) {
            final float xc = scrolledXFloat - (float) target.mLeft;
            final float yc = scrolledYFloat - (float) target.mTop;
            mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
            ev.setAction(MotionEvent.ACTION_CANCEL);
            ev.setLocation(xc, yc);
            if (!target.dispatchTouchEvent(ev)) {
                // target didn't handle ACTION_CANCEL. not much we can do
                // but they should have.
            }
            //at The target the Clear 
            mMotionTarget = null ;
             // the Do not dispatch the this Event to View Our own, already Because WE
             // the SAW IT the when the Intercepting; WE want to give the Just at The following
             // Event at The Normal to onTouchEvent (). 
            return  to true ; 
        } 
when we disallowIntercept set to true,! disallowIntercept directly to false, so the intercept method body is skipped, and also ineffective.

The above processes are normal distribution processes, if not find a suitable sub-View, or child View of dispatchTouchEvent returns false how to do?

 

This is part of the code above down event

IF (child.dispatchTouchEvent (EV)) {
  mMotionTarget = Child;
  return to true;
}
only to return in child.dispatchTouchEvent (ev) true, and will think you have found View capable of handling the current event, namely mMotionTarget = child, otherwise still null

Final View target = mMotionTarget;
         IF (target == null ) {
             // We do Not have have target A, the this means WE're Handling The
             // Event AS A Regular View. 
            ev.setLocation (XF, YF);
             IF ( (mPrivateFlags & CANCEL_NEXT_UP_EVENT) = 0! ) { 
                ev.setAction (MotionEvent.ACTION_CANCEL); 
                mPrivateFlags & = ~ CANCEL_NEXT_UP_EVENT; 
            } 
            return  Super .dispatchTouchEvent (EV); 
        } 
we do not have a target element can handle the event, means that we need deal with their own

to sum up:

1. If ViewGroup found View can handle the event, the processing directly to the sub-View, their onTouchEvent not be triggered.

2. by replication onInterceptTouchEvent (ev) method, child View intercept events (ie, return true), the event to deal with their own, will own the corresponding method execution onTouchEvent

3. sub-View by calling getParent () requestDisallowInterceptTouchEvent (true); ViewGroup prevent or intercept its MOVE UP events;

 

Guess you like

Origin www.cnblogs.com/lianzhen/p/11276961.html