Android ViewGroup event distribution

Then last Android View event distribution Benpian to analyze ViewGroup event distribution (source-based Android3.0)

ViewGroup event distribution:

Before you begin we must first be clear, Android either measure, layout, or draw all that is descending from the parent to the child view layout layer by layer, of course, event distribution is no exception, so every time the trigger event must touch the screen the triggering event is the first parent layout, and then a layer of the corresponding sub-view, understand this conclusion dispatchTouchEvent method combined with a touch screen on each article mentioned must trigger view, we find the corresponding ViewGroup in this method, and event distribution ViewGroup precisely from this method:

/**
     * {@inheritDoc}
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (!onFilterTouchEventForSecurity(ev)) {
            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) {
                // this is weird, we got a pen down, but we thought it was
                // already down!
                // XXX: We should probably send an ACTION_UP to the current
                // target.
                mMotionTarget = null;
            }
            // If we're disallowing intercept or if we're allowing and we didn't
            // intercept
            if (disallowIntercept || !onInterceptTouchEvent(ev)) {
                // reset this event's 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 (child.dispatchTouchEvent(ev))  {
                                // Event handled, we have a target now.
                                mMotionTarget = child;
                                return true;
                            }
                            // The event didn't get handled, try the next view.
                            // Don't reset the event's location, it's not
                            // necessary here.
                        }
                    }
                }
            }
        }

        boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) ||
                (action == MotionEvent.ACTION_CANCEL);

        if (isUpOrCancel) {
            // Note, we've already copied the previous state to our local
            // variable, so this takes effect on the next event
            mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
        }

        // The event wasn't an ACTION_DOWN, dispatch it to our target if
        // we have one.
        final View target = mMotionTarget;
        if (target == null) {
            // We don't have a target, 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);
        }

        // if have a target, see if we're allowed to and want to intercept its
        // events
        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.
            }
            // clear the target
            mMotionTarget = null;
            // Don't dispatch this event to our own view, because we already
            // saw it when intercepting; we just want to give the following
            // event to the normal onTouchEvent().
            return true;
        }

        if (isUpOrCancel) {
            mMotionTarget = null;
        }

        // finally offset the event to the target's coordinate system and
        // dispatch the event.
        final float xc = scrolledXFloat - (float) target.mLeft;
        final float yc = scrolledYFloat - (float) target.mTop;
        ev.setLocation(xc, yc);

        if ((target.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
            ev.setAction(MotionEvent.ACTION_CANCEL);
            target.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
            mMotionTarget = null;
        }

        return target.dispatchTouchEvent(ev);
    }

ViewGroup view with respect to dispatchTouchEvent method in which a lot longer, we pick the focus look. In determining the action to occur if a judge after disallowIntercept || down! OnInterceptTouchEvent (ev), comments can be seen by intercepting disabled or not disabled but does not need to intercept the event will enter if internal judgment, the judgment of internally viewGroup sub-view of all the sub-view is traversed to determine whether the current hit area in view of a child (that is, to get the child view click), then call through if (child.dispatchTouchEvent (ev)) of dispatchTouchEvent () method, if the child return true view of dispatchTouchEvent () method will be assigned to the sub-view and mMotionTarget ViewGroup method of dispatchTouchEvent true, namely sub-view event processing and returns true, the parent view will no longer deal with the incident.

And if not clicked after traversing the sub-view that is mMotionTarget not been assigned, or sub-view of divpatchTouchEvent returns false, it will continue downward, we see that if mMotionTarget is null after the calls return super.dispatchTouchEvent (ev) while dispatchTouchEvent ViewGroup method inherited from View so here is called View of handling the incident.

Also here || for disallowIntercept onInterceptTouchEvent (ev) two reference values ​​of the judgment to be explained:! DisallowIntercept refers to whether to disable the swap event interception function, the default is false, you can also modify this value by calling requestDisallowInterceptTouchEvent method. ! OnInterceptTouchEvent (ev) is the return value of onInterceptTouchEvent negated! This means that if we return false onInterceptTouchEvent method, will make the second is true, to enter into the internal conditions of the judgment, if we return true onInterceptTouchEvent method, will make the second is false, so out of this conditional.

So far ViewGroup event for distribution on the end, we can know the following conclusions:

  • 1.Android event distribution is from father to son
  • 2. Can be in viewgroup by onInterceptTouchEvent event interceptor method returns true if the event does not pass by themselves to deal with the child view, if it returns false, the event will be transmitted to the child view, the default method returns false.
  • 3. If the event is handled by a sub-view, parent view will not receive any events.

view group events distributed call graph:

 

 

 

References:

https://blog.csdn.net/guolin_blog/article/details/9153747

发布了10 篇原创文章 · 获赞 4 · 访问量 998

Guess you like

Origin blog.csdn.net/qq_25097107/article/details/89298647