Android触摸事件总结如下:

1、触摸事件分发顺序

dispatchTouchEvent:触摸事件从上向下分发

onInterTouchEvent:拦截事件,返回true表示拦截成功,交由自己的onTouchEvent处理。

onTouchEvent:消费事件,如果消费返回true,否则返回false,事件再依次向上传递。


2、层级顺序

Activity--------layout中的根节点------ViewGroup-----当前targetView.

1.1 Activity中

dispatchTouchEvent

   

   public boolean dispatchTouchEvent(MotionEvent ev) {        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            onUserInteraction();        }        if (getWindow().superDispatchTouchEvent(ev)) { //交由view处理            return true;        }        return onTouchEvent(ev); //如果view不消费事件,则交给自己的onTouchEvent处理.    }

onTouchEvent

    消费事件


1.2 ViewGroup中

dispatchTouchEvent

    ViewGroup重写了View中的dispatchTouchEvent

    

          // Check for interception.            final boolean intercepted;            if (actionMasked == MotionEvent.ACTION_DOWN                    || mFirstTouchTarget != null) {                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; //targetView是否设置了requestDisallowInterceptTouchEvent(true)                if (!disallowIntercept) {                    intercepted = onInterceptTouchEvent(ev); //执行事件拦截                    ev.setAction(action); // restore action in case it was changed                } else {                    intercepted = false; //targetView不允许父容器拦截事件                }            } else {                // There are no touch targets and this action is not an initial down                // so this view group continues to intercept touches.                intercepted = true;            }

onInterceptTouchEvent

      拦截事件

onTouchEvent

     消费事件,同View

1.3 子View中

dispatchTouchEvent

     

 if (li != null && li.mOnTouchListener != null                    && (mViewFlags & ENABLED_MASK) == ENABLED                    && li.mOnTouchListener.onTouch(this, event)) { //如果当前View enabled,则优先执行onTouchListener,如果返回true,则不再执行onTouchEvent                result = true;            }            if (!result && onTouchEvent(event)) { //执行onTouchEvent                result = true;            }

onTouchEvent

  public boolean onTouchEvent(MotionEvent event) {        final float x = event.getX();        final float y = event.getY();        final int viewFlags = mViewFlags;        final int action = event.getAction();
        //如果当前View.setEnabled(false);        if ((viewFlags & ENABLED_MASK) == DISABLED) {            if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {                setPressed(false); //还原按下状态            }            // A disabled view that is clickable still consumes the touch            // events, it just doesn't respond to them.            return (((viewFlags & CLICKABLE) == CLICKABLE                    || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)                    || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE);        }        if (mTouchDelegate != null) {             if (mTouchDelegate.onTouchEvent(event)) { //事件委托处理                return true;            }        }         //可点击或长按可点击         if (((viewFlags & CLICKABLE) == CLICKABLE ||                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||                (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {            switch (action) {                case MotionEvent.ACTION_UP:                    boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;                    if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {                        // take focus if we don't have it already and we should in                        // touch mode.                        boolean focusTaken = false;                        if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {                            focusTaken = requestFocus();                        }                        if (prepressed) {                            // The button is being released before we actually                            // showed it as pressed.  Make it show the pressed                            // state now (before scheduling the click) to ensure                            // the user sees it.                            setPressed(true, x, y);                       }                          //如果还未执行长按事件(按下的时间不够或者没有设置LongClickListener                        if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {                            // This is a tap, so remove the longpress check                            removeLongPressCallback();//移除长按回调                            // Only perform take click actions if we were in the pressed state                            if (!focusTaken) {                                // Use a Runnable and post this rather than calling                                // performClick directly. This lets other visual state                                // of the view update before click actions start.                                if (mPerformClick == null) {                                    mPerformClick = new PerformClick();                                }                                if (!post(mPerformClick)) {                                    performClick(); //执行点击事件                                }                            }                        }                        if (mUnsetPressedState == null) {                            mUnsetPressedState = new UnsetPressedState();                        }                        if (prepressed) {                            postDelayed(mUnsetPressedState,                                    ViewConfiguration.getPressedStateDuration());                        } else if (!post(mUnsetPressedState)) {                            // If the post failed, unpress right now                            mUnsetPressedState.run();                        }                        removeTapCallback();                    }                    mIgnoreNextUpEvent = false;                    break;                case MotionEvent.ACTION_DOWN:                    mHasPerformedLongPress = false;                    if (performButtonActionOnTouchDown(event)) {                        break;                    }                    // Walk up the hierarchy to determine if we're inside a scrolling container.                    boolean isInScrollingContainer = isInScrollingContainer();                    // For views inside a scrolling container, delay the pressed feedback for                    // a short period in case this is a scroll.                    if (isInScrollingContainer) {                        mPrivateFlags |= PFLAG_PREPRESSED;                        if (mPendingCheckForTap == null) {                            mPendingCheckForTap = new CheckForTap();                        }                        mPendingCheckForTap.x = event.getX();                        mPendingCheckForTap.y = event.getY();                        postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());                    } else {                        // Not inside a scrolling container, so show the feedback right away                        setPressed(true, x, y);                        checkForLongClick(0);                    }                    break;                case MotionEvent.ACTION_CANCEL:                    setPressed(false);                    removeTapCallback();                    removeLongPressCallback();                    mInContextButtonPress = false;                    mHasPerformedLongPress = false;                    mIgnoreNextUpEvent = false;                    break;                case MotionEvent.ACTION_MOVE:                    drawableHotspotChanged(x, y);                    // Be lenient about moving outside of buttons                    if (!pointInView(x, y, mTouchSlop)) { //如果触摸点不在当前View上,则移除点击事件回调                        // Outside button                        removeTapCallback();                        if ((mPrivateFlags & PFLAG_PRESSED) != 0) {                            // Remove any future long press/tap checks                            removeLongPressCallback();                            setPressed(false);                        }                    }                    break;            }            return true;        }        return false;    }


dispatchTouchEvent、onTouchEvent、OnTouchListener、onClickListener的执行优先级?

这个要分二种情况:

1)如果点击的是容器类ViewGroup

dispatchTouchEvent----onInterceptTouchEvent-----onTouchListener----onTouchEvent(ACTION_UP时检测执行OnClickListener)

2)如果点击的是非容器类View,比如TextView

dispatchTouchEvent中执行onTouchListener,onTouch返回false,才执行onTouchEvent(ACTION_UP时检测执行OnClickListener)





更多相关文章

  1. Android长按事件和点击事件问题处理,OnItemLongClickListener和On
  2. Android触摸事件分发机制(1)之View
  3. Android事件分发机制研究
  4. Android 4.0 事件输入(Event Input)系统
  5. android视图组件容器组件与布局管理器LinearLayout
  6. android中的事件总线
  7. view对touch事件的处理
  8. Android Notes(06) - Touch事件分发响应机制
  9. android中上层是如何接收按键事件的

随机推荐

  1. Apache Doris : 一个开源 MPP 数据库的架
  2. 基于行列式点过程的推荐多样性提升算法
  3. 如何在Safari上屏蔽网站?
  4. 苹果Mac App Store 的界面语言变成英文了
  5. 推荐系统燃料:数据那些事儿
  6. 常用的报表工具有哪些_目前最流行的报表
  7. 国外有Tableau,国内有思迈特软件Smartbi
  8. 应用计量经济学现状: 因果推断与政策评估
  9. iOS发开之如何成为一名高手?
  10. python+opencv实现连通区域分离