2018-05-31 17:23:46

Note: 这里的源码来自Android 2.3.6,这个版本的代码比较简单,适合理解Touch事件的传递原理。后续版本源码复杂了很多,但是原理都是类似的。

2个方法源码较多,在这里记录下。

View.java

  1  /**
  2      * Implement this method to handle touch screen motion events.
  3      *
  4      * @param event The motion event.
  5      * @return True if the event was handled, false otherwise.
  6      */
  7     public boolean onTouchEvent(MotionEvent event) {
  8         final int viewFlags = mViewFlags;
  9 
 10         if ((viewFlags & ENABLED_MASK) == DISABLED) {
 11             // A disabled view that is clickable still consumes the touch
 12             // events, it just doesn't respond to them.
 13             return (((viewFlags & CLICKABLE) == CLICKABLE ||
 14                     (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));
 15         }
 16 
 17         if (mTouchDelegate != null) {
 18             if (mTouchDelegate.onTouchEvent(event)) {
 19                 return true;
 20             }
 21         }
 22 
 23         if (((viewFlags & CLICKABLE) == CLICKABLE ||
 24                 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
 25             switch (event.getAction()) {
 26                 case MotionEvent.ACTION_UP:
 27                     boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;
 28                     if ((mPrivateFlags & PRESSED) != 0 || prepressed) {
 29                         // take focus if we don't have it already and we should in
 30                         // touch mode.
 31                         boolean focusTaken = false;
 32                         if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
 33                             focusTaken = requestFocus();
 34                         }
 35 
 36                         if (!mHasPerformedLongPress) {
 37                             // This is a tap, so remove the longpress check
 38                             removeLongPressCallback();
 39 
 40                             // Only perform take click actions if we were in the pressed state
 41                             if (!focusTaken) {
 42                                 // Use a Runnable and post this rather than calling
 43                                 // performClick directly. This lets other visual state
 44                                 // of the view update before click actions start.
 45                                 if (mPerformClick == null) {
 46                                     mPerformClick = new PerformClick();
 47                                 }
 48                                 if (!post(mPerformClick)) {
 49                                     performClick();
 50                                 }
 51                             }
 52                         }
 53 
 54                         if (mUnsetPressedState == null) {
 55                             mUnsetPressedState = new UnsetPressedState();
 56                         }
 57 
 58                         if (prepressed) {
 59                             mPrivateFlags |= PRESSED;
 60                             refreshDrawableState();
 61                             postDelayed(mUnsetPressedState,
 62                                     ViewConfiguration.getPressedStateDuration());
 63                         } else if (!post(mUnsetPressedState)) {
 64                             // If the post failed, unpress right now
 65                             mUnsetPressedState.run();
 66                         }
 67                         removeTapCallback();
 68                     }
 69                     break;
 70 
 71                 case MotionEvent.ACTION_DOWN:
 72                     if (mPendingCheckForTap == null) {
 73                         mPendingCheckForTap = new CheckForTap();
 74                     }
 75                     mPrivateFlags |= PREPRESSED;
 76                     mHasPerformedLongPress = false;
 77                     postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
 78                     break;
 79 
 80                 case MotionEvent.ACTION_CANCEL:
 81                     mPrivateFlags &= ~PRESSED;
 82                     refreshDrawableState();
 83                     removeTapCallback();
 84                     break;
 85 
 86                 case MotionEvent.ACTION_MOVE:
 87                     final int x = (int) event.getX();
 88                     final int y = (int) event.getY();
 89 
 90                     // Be lenient about moving outside of buttons
 91                     int slop = mTouchSlop;
 92                     if ((x < 0 - slop) || (x >= getWidth() + slop) ||
 93                             (y < 0 - slop) || (y >= getHeight() + slop)) {
 94                         // Outside button
 95                         removeTapCallback();
 96                         if ((mPrivateFlags & PRESSED) != 0) {
 97                             // Remove any future long press/tap checks
 98                             removeLongPressCallback();
 99 
100                             // Need to switch from pressed to not pressed
101                             mPrivateFlags &= ~PRESSED;
102                             refreshDrawableState();
103                         }
104                     }
105                     break;
106             }
107             return true;
108         }
109 
110         return false;
111     }
View Code

 

ViewGroup.java

  1     /**
  2      * {@inheritDoc}
  3      */
  4     @Override
  5     public boolean dispatchTouchEvent(MotionEvent ev) {
  6         if (!onFilterTouchEventForSecurity(ev)) {
  7             return false;
  8         }
  9 
 10         final int action = ev.getAction();
 11         final float xf = ev.getX();
 12         final float yf = ev.getY();
 13         final float scrolledXFloat = xf + mScrollX;
 14         final float scrolledYFloat = yf + mScrollY;
 15         final Rect frame = mTempRect;
 16 
 17         boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
 18 
 19         if (action == MotionEvent.ACTION_DOWN) {
 20             if (mMotionTarget != null) {
 21                 // this is weird, we got a pen down, but we thought it was
 22                 // already down!
 23                 // XXX: We should probably send an ACTION_UP to the current
 24                 // target.
 25                 mMotionTarget = null;
 26             }
 27             // If we're disallowing intercept or if we're allowing and we didn't
 28             // intercept
 29             if (disallowIntercept || !onInterceptTouchEvent(ev)) {
 30                 // reset this event's action (just to protect ourselves)
 31                 ev.setAction(MotionEvent.ACTION_DOWN);
 32                 // We know we want to dispatch the event down, find a child
 33                 // who can handle it, start with the front-most child.
 34                 final int scrolledXInt = (int) scrolledXFloat;
 35                 final int scrolledYInt = (int) scrolledYFloat;
 36                 final View[] children = mChildren;
 37                 final int count = mChildrenCount;
 38 
 39                 for (int i = count - 1; i >= 0; i--) {
 40                     final View child = children[i];
 41                     if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
 42                             || child.getAnimation() != null) {
 43                         child.getHitRect(frame);
 44                         if (frame.contains(scrolledXInt, scrolledYInt)) {
 45                             // offset the event to the view's coordinate system
 46                             final float xc = scrolledXFloat - child.mLeft;
 47                             final float yc = scrolledYFloat - child.mTop;
 48                             ev.setLocation(xc, yc);
 49                             child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
 50                             if (child.dispatchTouchEvent(ev))  {
 51                                 // Event handled, we have a target now.
 52                                 mMotionTarget = child;
 53                                 return true;
 54                             }
 55                             // The event didn't get handled, try the next view.
 56                             // Don't reset the event's location, it's not
 57                             // necessary here.
 58                         }
 59                     }
 60                 }
 61             }
 62         }
 63 
 64         boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) ||
 65                 (action == MotionEvent.ACTION_CANCEL);
 66 
 67         if (isUpOrCancel) {
 68             // Note, we've already copied the previous state to our local
 69             // variable, so this takes effect on the next event
 70             mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
 71         }
 72 
 73         // The event wasn't an ACTION_DOWN, dispatch it to our target if
 74         // we have one.
 75         final View target = mMotionTarget;
 76         if (target == null) {
 77             // We don't have a target, this means we're handling the
 78             // event as a regular view.
 79             ev.setLocation(xf, yf);
 80             if ((mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
 81                 ev.setAction(MotionEvent.ACTION_CANCEL);
 82                 mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
 83             }
 84             return super.dispatchTouchEvent(ev);
 85         }
 86 
 87         // if have a target, see if we're allowed to and want to intercept its
 88         // events
 89         if (!disallowIntercept && onInterceptTouchEvent(ev)) {
 90             final float xc = scrolledXFloat - (float) target.mLeft;
 91             final float yc = scrolledYFloat - (float) target.mTop;
 92             mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
 93             ev.setAction(MotionEvent.ACTION_CANCEL);
 94             ev.setLocation(xc, yc);
 95             if (!target.dispatchTouchEvent(ev)) {
 96                 // target didn't handle ACTION_CANCEL. not much we can do
 97                 // but they should have.
 98             }
 99             // clear the target
100             mMotionTarget = null;
101             // Don't dispatch this event to our own view, because we already
102             // saw it when intercepting; we just want to give the following
103             // event to the normal onTouchEvent().
104             return true;
105         }
106 
107         if (isUpOrCancel) {
108             mMotionTarget = null;
109         }
110 
111         // finally offset the event to the target's coordinate system and
112         // dispatch the event.
113         final float xc = scrolledXFloat - (float) target.mLeft;
114         final float yc = scrolledYFloat - (float) target.mTop;
115         ev.setLocation(xc, yc);
116 
117         if ((target.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
118             ev.setAction(MotionEvent.ACTION_CANCEL);
119             target.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
120             mMotionTarget = null;
121         }
122 
123         return target.dispatchTouchEvent(ev);
124     }
View Code

 

 posted on 2018-05-31 17:25  wlrhnh  阅读(162)  评论(0编辑  收藏  举报