美文网首页
滑动冲突

滑动冲突

作者: fuc_9034 | 来源:发表于2019-06-25 15:58 被阅读0次

MotionEvent

事件分发、拦截与消费

  • 上表中勾和叉表示的是这3种事件的相关方法在Activity、ViewGroup、View中是否含有该方法

分发流程

Activity.dispatchTouchEvent()
>PhoneWindow.superDispatchTouchEvent()
>DecorView.superDispatchTouchEvent()
>ViewGroup.dispatchTouchEvent()
>View.dispatchTouchEvent()
>View.onTouchEvent()

onTouch、onClick之间的关系

public boolean dispatchTouchEvent(MotionEvent event) {
     ........省略
      if (onFilterTouchEventForSecurity(event)) {
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                result = true;
            }
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }
        ........省略
}

如果li.mOnTouchListener.onTouch()为false, result也为false,那么onTouchEvent()也会执行,ACTION_UP事件里performClickInternal() > performClick() > li.mOnClickListener.onClick(),说明了onTouch()先于onClick()执行。反过来,如果onTouch()为true,那么result也为true,if判断里onTouchEvent()就不会执行,onClick()也就不会被调用了。

ACTION_DOWN事件重要方法:

  • buildTouchDispatchChildList():按照z轴对子view进行排序
  • dispatchTransformedTouchEvent():事件分发给谁来处理

事件拦截

 final boolean intercepted;
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || mFirstTouchTarget != null) {
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                //disallowIntercept为true,则onInterceptTouchEvent()不执行
                if (!disallowIntercept) {
                    //是否拦截事件的传递
                    intercepted = onInterceptTouchEvent(ev);
                    ev.setAction(action); // restore action in case it was changed
                } else {
                    intercepted = false;
                }
            } else {
                // There are no touch targets and this action is not an initial down
                // so this view group continues to intercept touches.
                intercepted = true;
            }

内部拦截法:

ViewParent

 @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        //dispatchTouchEvent()会对ACTION_DOWN事件调用resetTouchState()
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            super.onInterceptTouchEvent(event);
            return false;
        }
        return true;
    }

ChildView

 private int mLastX, mLastY;

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                int deltaX = x - mLastX;
                int deltaY = y - mLastY;
                if (Math.abs(deltaX) > Math.abs(deltaY)) {
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
                break;
            }
            case MotionEvent.ACTION_UP: {
                break;
            }
            default:
                break;
        }

        mLastX = x;
        mLastY = y;

        return super.dispatchTouchEvent(event);
    }

外部拦截法:

ViewParent

 private int mLastX, mLastY;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {

        int x = (int) event.getX();
        int y = (int) event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                mLastX = (int) event.getX();
                mLastY = (int) event.getY();
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                int deltaX = x - mLastX;
                int deltaY = y - mLastY;
                if (Math.abs(deltaX) > Math.abs(deltaY)) {
                    return true;
                }
                break;
            }
            case MotionEvent.ACTION_UP: {
                break;
            }
            default:
                break;
        }

        return super.onInterceptTouchEvent(event);
    }

以上只是2个例子,实际案例中具体情况具体分析,但知道原理了就好解决滑动冲突问题了:
父容器拦截事件:
onInterceptTouchEvent()=true
请求父容器不要拦截事件:
getParent().requestDisallowInterceptTouchEvent(true)

相关文章

  • Android View 事件体系笔记 (三):View滑动冲突

    一、View 滑动冲突背景 1.1 View 滑动冲突常见场景 场景1 —— 外部和内部横竖滑动交错冲突 场景2 ...

  • View的事件体系(五)View滑动冲突的解决方案

    一.滑动冲突产生的原因 在界面中,只要内外两层同时可以滑动,这个时候就会产生滑动冲突。 二.常见的滑动冲突场景 外...

  • 滑动冲突及其解决办法

    滑动冲突产生的愿因 在界面中只要内外两层同时可以滑动,这个时候就会产生滑动冲突。 滑动冲突产生的场景 场景1 --...

  • Android View的事件体系(五) View的滑动冲突

    滑动冲突时如何产生的呢?在界面中只要内外两层同时可以滑动,这个时候就会产生滑动冲突. 常见的滑动冲突场景 1 外部...

  • 滑动事件冲突

    滑动事件冲突 一般分三种: 滑动方向一致导致的冲突 滑动方向不一致导致的冲突 滑动方向的各种叠加导致的冲突 解决方...

  • View的滑动冲突

    前言:滑动冲突是如何产生的呢?其实在界面中只要内外两层同时可以滑动,这个时候就会产生滑动冲突。如何解决滑动冲突呢?...

  • Android滑动事件冲突解决方法

    1.Android滑动事件冲突解决办法 滑动事件的冲突包括两种情形: 不同方向的滑动冲突:比如ScrollView...

  • ScrollView 嵌套 RecyclerVeiw, 轻松解决

    滑动冲突 在开发android中, 滑动冲突是一常见的事件冲突。列如:在scrollView中嵌套listView...

  • Android View | View 的滑动冲突

    滑动冲突在实际项目中十分常见,解决滑动冲突的核心是结合事件的分发机制,了解事件的分发可参考这里。 常见的滑动冲突场...

  • 滑动冲突处理(一)

    滑动冲突场景:外层横向滑动,内层竖向滑动。这里通过外层拦截的方式来处理冲突。 注意:例子中得布局是ViewGrou...

网友评论

      本文标题:滑动冲突

      本文链接:https://www.haomeiwen.com/subject/dataqctx.html