View和ViewGroup的事件分发总结

来源:互联网 发布:郑雨盛 知乎 编辑:程序博客网 时间:2024/05/06 07:54

View事件分发:

当为一个Button设置OnClickListener事件后,单击该Button,首先会调用View的dispatchTouchEvent()方法进行事件分发,Button是View的子类,故调用View的该方法,

当mOnTouchListener!=null,并且该view为enable激活状态的时候,以及onTouch()方法返回true的时候才会调用onTouchEvent()方法。我们在为View设置OnTouchListener的时候默认为mOnTouchListener赋值,并且Button默认为enable状态,所以当onTouch()返回false的时候,dispatchTouchEvent()方法直接返回true,不再响应事件.

public boolean dispatchTouchEvent(MotionEvent event) {          if (!onFilterTouchEventForSecurity(event)) {              return false;          }            if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&                  mOnTouchListener.onTouch(this, event)) {              return true;          }          return onTouchEvent(event);      }  

如果为该Button也设置了OnClickListener,首先会执行onTouch()方法再执行onClick()方法,从上面可以得出onClick()方法与onTouchEvent(event)方法有关.

当event.getAction()==ACTION_UP时,会首先判断是否是OnLongClickListener(500ms后),否则执行performClick(),也就是onClick().

如果我们也设置了OnLongClickListener,那么会先执行onLongClick()方法,当返回值为false时(默认false),会继续执行onClick方法,否则不再继续执行.

public boolean onTouchEvent(MotionEvent event) {          final int viewFlags = mViewFlags;            if ((viewFlags & ENABLED_MASK) == DISABLED) {                      return (((viewFlags & CLICKABLE) == CLICKABLE ||                      (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));          }           if (mTouchDelegate != null) {              if (mTouchDelegate.onTouchEvent(event)) {                  return true;              }          }            if (((viewFlags & CLICKABLE) == CLICKABLE ||                  (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {              switch (event.getAction()) {                  case MotionEvent.ACTION_UP:                      boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;                      if ((mPrivateFlags & PRESSED) != 0 || prepressed) {                                              if (!mHasPerformedLongPress) {                              removeLongPressCallback();                                                       if (!focusTaken) {                                                               if (mPerformClick == null) {                                      mPerformClick = new PerformClick();                                  }                                  if (!post(mPerformClick)) {                                      performClick();                                  }                              }                          }                                              }                      break;                    case MotionEvent.ACTION_DOWN:                      if (mPendingCheckForTap == null) {                          mPendingCheckForTap = new CheckForTap();                      }                      mPrivateFlags |= PREPRESSED;                      mHasPerformedLongPress = false;                      postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());                      break;                    case MotionEvent.ACTION_CANCEL:                      mPrivateFlags &= ~PRESSED;                      refreshDrawableState();                      removeTapCallback();                      break;                    case MotionEvent.ACTION_MOVE:                                         break;              }              return true;          }            return false;      }  


注意:一般情况下,onTouchEvent()都是返回true的,也是就当onTouchEvent()被调用的时候dispatchTouchEvent()的返回值一样,当onTouchEvent()返回true,剩下的action才能得以执行.


ViewGroup事件分发:

其实Android事件分发是先传递到ViewGroup,再由ViewGroup传递到View的。,当一个ViewGroup中的一个子View发出onTouch事件的时候,首先由父类的dispatchTouchEvent()进行事件分发,再调用onInterceptTouchEvent方法对事件进行拦截(默认返回false),返回true则对事件进行拦截,不再对子View进行事件分发.

如果子View消费掉事件后,ViewGroup中将接收不到任何事件。

public boolean onInterceptTouchEvent(MotionEvent ev) {      return false;  } 
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;      if (action == MotionEvent.ACTION_DOWN) {          if (mMotionTarget != null) {              mMotionTarget = null;          }          if (disallowIntercept || !onInterceptTouchEvent(ev)) {              ev.setAction(MotionEvent.ACTION_DOWN);              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)) {                          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))  {                              mMotionTarget = child;                              return true;                          }                      }                  }              }          }      }  

disallowIntercept 这个参数指是否禁用掉拦截功能,默认为false,子view可以通过调用getParent().requestDisallowInterceptTouchEvent(true)阻止ViewGroup对其MOVE或者UP事件进行拦截;同样ViewGroup也可以通过该属性返回true,拦截子View的事件,自己进行处理。


0 0
原创粉丝点击