Android事件机制之ViewPager的分发与拦截

事件分发:public boolean dispatchTouchEvent(MotionEvent ev)

当有监听到事件时,首先由Activity的捕获到,进入事件分发处理流程。Activity-->ViewGroup-->View,每一个事件自身都是具有分发事件的能力的,

如果dispatchTouchEvent返回了true,表示改事件在本层不再进行分发事件被自己消费了。至此,事件已经完结。

如果事件分发返回 false,表明事件在本层不再继续进行分发,并交由上层控件的onTouchEvent方法进行消费。

如果事件分发返回系统默认的 super.dispatchTouchEvent(ev),事件将分发给本层的事件拦截onInterceptTouchEvent 方法进行处理。


 

事件拦截:public boolean onInterceptTouchEvent(MotionEvent ev) 

如果 onInterceptTouchEvent 返回 true,则表示将事件进行拦截,并将拦截到的事件交由本层控件 的 onTouchEvent 进行处理;

如果返回结果是false;则表示不对事件进行拦截,事件得以成功分发到子View。并由子View的dispatchTouchEvent进行处理。

如果返回super.onInterceptTouchEvent(ev),事件默认不会被拦截,交由子View的dispatchTouchEvent进行处理。

 

 事件响应:public boolean onTouchEvent(MotionEvent ev)

如果onTouchEvent返回true,表示onTouchEvent处理完事件后消费了此次事件。

如果onTouchEvent返回false,事件在onTouchEvent中处理后DOWN方法,且有上层View的onTouchEvent进行处理MOVE和UP方法。

如果返回super.onTouchEvent(ev),则默认处理的逻辑和返回false时相同。(根据不同的View返回值可能不一样,我用viewpager返回时默认的用super。onTouchEvent(ev)实际上返回的是true,这个只是少数,所以读者们记住默认返回和false相同就行记住这个特例就行了)


总结下:Activity-->ViewGroup-->View当我们点击的时候实际上最外层的Activity最先进行事件分发,默认返回super.dispatchTouchEvent(ev),不拦截事件交给自身的onIntercepTouch(ev)方法执行,默认的话返回super事件也就是false不进行拦截交给ViewGroup的分发事件处理默认返回super.dispatchTouch(ev)处理,同样默认返回super不分发交给onIntercepTouch(ev)处理,默认返回super不拦截又交给View的分发事件处理,因为View的话没有拦截事件所以不会进行拦截所以在View的dispatchTouch(ev)分发中返回的super会默认的执行ontouchEvent(ev),默认的话返回super也就是false不进行处理,交给父类(ViewGroup)的onTouchView处理,默认返回的是super也就是false,又交给父类(Activity)的onTouchView处理

接下来就是重头戏了,我在做项目的时候因为需求所以要让ViewPager不能够进行左右滑动,也在网上查询了一系列方法,都是告诉我直接写一个类然后继承ViewPager然后在这个类中重写onTouchEvent方法然后把默认的super改成false就可以了。但是这个时候肯定有读者有疑问了,不是说OntouchEvent方法里面的super和false一样的嘛都是处理下DOWN事件然后回调父类去实现MOVE和UP事件嘛,为什么super能够滑动而false不能滑动呢。这个时候我们通过代码进行观察下。


情形①:

MyViewPageonTouchEvent直接返回false


可以看出,直接返回false的结果是,在MyViewPage到达onTouchEvent之后直接交还给activityonTouchEvent进行处理,而且后续的MoveUp事件不再经过MyViewPage了。



情形②:MyViewPageonTouchEvent直接返回true



在Down事件之后,onTouchEvent返回true,消费该系列的事件,故后续的MoveUp事件会在dispatch之后直接交由onTouch处理;

情形③:

MyViewPageonTouchEvent返回super方法:

相关代码以及log

代码:

boolean b = super.onTouchEvent(event);
Log.d("A","MyViewPage:onTouchEvent--"+b);
return b;


代码上可以看出,其实return返回的也是true,仅仅是多了一个super操作。

下面看下源码做了哪些操作:

 

 

    @Override

    public boolean onTouchEvent(MotionEvent ev) {

        if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {

            // Don't handle edge touches immediately -- they may actually belong to one of our

            // descendants.

            return false;

        }

 

        if (mAdapter == null || mAdapter.getCount() == 0) {

            // Nothing to present or scroll; nothing to touch.

            return false;

        }

 

        if (mVelocityTracker == null) {

            mVelocityTracker = VelocityTracker.obtain();

        }

        mVelocityTracker.addMovement(ev);

 

        final int action = ev.getAction();

        boolean needsInvalidate = false;

 

        switch (action & MotionEvent.ACTION_MASK) {

            case MotionEvent.ACTION_DOWN: {

                mScroller.abortAnimation();

                mPopulatePending = false;

                populate();

 

                // Remember where the motion event started

                mLastMotionX = mInitialMotionX = ev.getX();

                mLastMotionY = mInitialMotionY = ev.getY();

                mActivePointerId = ev.getPointerId(0);

                break;

            }

            case MotionEvent.ACTION_MOVE:

                if (!mIsBeingDragged) {

                    final int pointerIndex = ev.findPointerIndex(mActivePointerId);

                    final float x = ev.getX(pointerIndex);

                    final float xDiff = Math.abs(x - mLastMotionX);

                    final float y = ev.getY(pointerIndex);

                    final float yDiff = Math.abs(y - mLastMotionY);

                    if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);

                    if (xDiff > mTouchSlop && xDiff > yDiff) {

                        if (DEBUG) Log.v(TAG, "Starting drag!");//

                        mIsBeingDragged = true;

                        requestParentDisallowInterceptTouchEvent(true);

                        mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop :

                                mInitialMotionX - mTouchSlop;

                        mLastMotionY = y;

                        setScrollState(SCROLL_STATE_DRAGGING);

                        setScrollingCacheEnabled(true);

 

                        // Disallow Parent Intercept, just in case

                        ViewParent parent = getParent();

                        if (parent != null) {

                            parent.requestDisallowInterceptTouchEvent(true);

                        }

                    }

                }

                // Not else! Note that mIsBeingDragged can be set above.

                if (mIsBeingDragged) {

                    // Scroll to follow the motion event

                    final int activePointerIndex = ev.findPointerIndex(mActivePointerId);

                    final float x = ev.getX(activePointerIndex);

                    needsInvalidate |= performDrag(x);

                }

                break;

            case MotionEvent.ACTION_UP:

                if (mIsBeingDragged) {

                    final VelocityTracker velocityTracker = mVelocityTracker;

                    velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);

                    final int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId);

 

                    mPopulatePending = true;

 

                    final float scrollStart = getScrollStart();

                    final float scrolledPages = scrollStart / getPaddedWidth();

                    final ItemInfo ii = infoForFirstVisiblePage();

                    final int currentPage = ii.position;

                    final float nextPageOffset;

                    if (isLayoutRtl()) {

                        nextPageOffset = (ii.offset - scrolledPages) / ii.widthFactor;

                    }  else {

                        nextPageOffset = (scrolledPages - ii.offset) / ii.widthFactor;

                    }

 

                    final int activePointerIndex = ev.findPointerIndex(mActivePointerId);

                    final float x = ev.getX(activePointerIndex);

                    final int totalDelta = (int) (x - mInitialMotionX);

                    final int nextPage = determineTargetPage(

                            currentPage, nextPageOffset, initialVelocity, totalDelta);

                    setCurrentItemInternal(nextPage, true, true, initialVelocity);

 

                    mActivePointerId = INVALID_POINTER;

                    endDrag();

                    mLeftEdge.onRelease();

                    mRightEdge.onRelease();

                    needsInvalidate = true;

                }

                break;

            case MotionEvent.ACTION_CANCEL:

                if (mIsBeingDragged) {

                    scrollToItem(mCurItem, true, 0, false);

                    mActivePointerId = INVALID_POINTER;

                    endDrag();

                    mLeftEdge.onRelease();

                    mRightEdge.onRelease();

                    needsInvalidate = true;

                }

                break;

            case MotionEvent.ACTION_POINTER_DOWN: {

                final int index = ev.getActionIndex();

                final float x = ev.getX(index);

                mLastMotionX = x;

                mActivePointerId = ev.getPointerId(index);

                break;

            }

            case MotionEvent.ACTION_POINTER_UP:

                onSecondaryPointerUp(ev);

                mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId));

                break;

        }

        if (needsInvalidate) {

            postInvalidateOnAnimation();

        }

        return true;

    }

 

从源码可以看出,在ACTION_MOVEcase中,进行了拖拽的操作。这就是和直接返回true的区别。所以,不论MyViewPage直接返回的是true或者是false,都没进行super里面的拖拽操作。



最后感谢一位大神帮助我解答所有的疑问,其实上诉的结论也都是他得出来的,很感谢为我做的这些。这位大神真的很优秀

 




  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值