使用viewPager時頁面中橫向滑動不響應viewPager左右滑動

場景例子: 

      我使用LazyViewPager 裏邊嵌套了幾個Fragment,其中有一個Fragment中是一個上下滑動的RecycleView,這個RecycleView中是多佈局實現的,其中有一個佈局是左右滑動的,這個時候我們會發現 , 在這個左右滑動佈局滑動到最左邊或者最右邊的時候ViewPager會響應左右滑動事件,現在的需求是手指滑動這個左右滑動佈局的時候即使滑動到左右頂端讓它劃不動,不能帶動ViewPager滑動。

解決:


這個問題想着應該是事件分發方法和Touch方法的關係 ,我們去看一下LazyViewPager的這兩個方法:

{
        


        final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;


        // Always take care of the touch gesture being complete.
        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
            // Release the drag.
            if (DEBUG) Log.v(TAG, "Intercept done!");
            mIsBeingDragged = false;
            mIsUnableToDrag = false;
            mActivePointerId = INVALID_POINTER;
            return false;
        }


        // Nothing more to do here if we have decided whether or not we
        // are dragging.
        if (action != MotionEvent.ACTION_DOWN) {
            if (mIsBeingDragged) {
                if (DEBUG) Log.v(TAG, "Intercept returning true!");
                return true;
            }
            if (mIsUnableToDrag) {
                if (DEBUG) Log.v(TAG, "Intercept returning false!");
                return false;
            }
        }


        switch (action) {
            case MotionEvent.ACTION_MOVE: {
                
                final int activePointerId = mActivePointerId;
                if (activePointerId == INVALID_POINTER) {
                    // If we don't have a valid id, the touch down wasn't on content.
                    break;
                }


                final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);
                final float x = MotionEventCompat.getX(ev, pointerIndex);
                final float dx = x - mLastMotionX;
                final float xDiff = Math.abs(dx);
                final float y = MotionEventCompat.getY(ev, pointerIndex);
                final float yDiff = Math.abs(y - mLastMotionY);
                final int scrollX = getScrollX();
                final boolean atEdge = (dx > 0 && scrollX == 0) || (dx < 0 && mAdapter != null &&
                        scrollX >= (mAdapter.getCount() - 1) * getWidth() - 1);
                if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);


                if (canScroll(this, false, (int) dx, (int) x, (int) y)) {
                    // Nested view has scrollable area under this point. Let it be handled there.
                    mInitialMotionX = mLastMotionX = x;
                    mLastMotionY = y;
                    return false;
                }
                if (xDiff > mTouchSlop && xDiff > yDiff) {
                    if (DEBUG) Log.v(TAG, "Starting drag!");
                    mIsBeingDragged = true;
                    setScrollState(SCROLL_STATE_DRAGGING);
                    mLastMotionX = x;
                    setScrollingCacheEnabled(true);
                } else {
                    if (yDiff > mTouchSlop) {
                        // The finger has moved enough in the vertical
                        // direction to be counted as a drag...  abort
                        // any attempt to drag horizontally, to work correctly
                        // with children that have scrolling containers.
                        if (DEBUG) Log.v(TAG, "Starting unable to drag!");
                        mIsUnableToDrag = true;
                    }
                }
                break;
            }


            case MotionEvent.ACTION_DOWN: {
               **
            }


            case MotionEventCompat.ACTION_POINTER_UP:
                **
        }
       
        return mIsBeingDragged;
    }
Down 和UP方法我們先不看
在這裏我們都知道這個方法的返回值代表這個ViewPager會不會去攔截事件,在返回true的時候回去攔截事件,然後這個事件就交給了ViewPager的Touch事件處理了,所以在這個地方我們在沒有滑動到橫向佈局的兩個頂端的時候它
一直返回的是false,但是在頂端的後就返回了true,這個mIsBeingDragged參數我們看一下在什麼位置被設置成了true , if (xDiff > mTouchSlop && xDiff > yDiff)  這個判斷的時候設置成了true,但是這個判斷是正確的,
那我們就想辦法在橫向滑動到頂端的時候返回false就行了,我們看if (canScroll(this, false, (int) dx, (int) x, (int) y)) 這個判斷是返回的false,這個好像符合我們的要求,看判斷的方法名canScroll,字面意思就很
明白了,能不能滑動,我們去看一下這個方法,
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
        if (v instanceof ViewGroup) {
            final ViewGroup group = (ViewGroup) v;
            final int scrollX = v.getScrollX();
            final int scrollY = v.getScrollY();
            final int count = group.getChildCount();
            // Count backwards - let topmost views consume scroll distance first.
            for (int i = count - 1; i >= 0; i--) {
                // TODO: Add versioned support here for transformed views.
                // This will not work for transformed views in Honeycomb+
                final View child = group.getChildAt(i);                
                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&
                        y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&
                        canScroll(child, true, dx, x + scrollX - child.getLeft(),
                                y + scrollY - child.getTop())) {
                    return true;
                }
            }
        }


        return checkV && ViewCompat.canScrollHorizontally(v, -dx);
    }
看了這個方法,原來是在這裏做了處理,這個方法的意思就是說,找到這個父級View然後循環他的子View看看還能不能滑動,返回true的意思就是上個方法中if語句成立,ViewPager不會攔截事件,就交給了橫向滑動的佈局,
這個時候我們就有思路了,在這個地方我是不是能把我想要處理的那個控件找出來然後見到他就return true 呢,這個時候我們找到我們要屏蔽ViewPager的控件看一下,我找到了這個RecycleView控件,
LinearLayoutManager layout = new LinearLayoutManager(m_Context);
layout.setOrientation(LinearLayoutManager.HORIZONTAL);
holder.rlv_.setLayoutManager(layout);        
holder.rlv_.setAdapter(adapter);
這個時候我們需要做一個唯一標識,我們在這裏setTag一下,holder.rlv_.setTag("dontTouch");標識一下不能被觸碰,然後我們在ViewPager中去找到他,
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
        if (v instanceof ViewGroup) {
            final ViewGroup group = (ViewGroup) v;
            final int scrollX = v.getScrollX();
            final int scrollY = v.getScrollY();
            final int count = group.getChildCount();
            // Count backwards - let topmost views consume scroll distance first.
            for (int i = count - 1; i >= 0; i--) {
                // TODO: Add versioned support here for transformed views.
                // This will not work for transformed views in Honeycomb+
                final View child = group.getChildAt(i);
                if(child instanceof RecyclerView && ((RecyclerView)child).getLayoutManager().getLayoutDirection() == HORIZONTAL){
                       if(child.getTag() != null && child.getTag().equals("dontTouch")){
                           return true ;
                       }
                }
                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&
                        y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&
                        canScroll(child, true, dx, x + scrollX - child.getLeft(),
                                y + scrollY - child.getTop())) {
                    return true;
                }
            }
        }


        return checkV && ViewCompat.canScrollHorizontally(v, -dx);
    }這個是改過之後的判斷方法,這裏我首先判斷了一下是不是橫向滑動的RecycleView,然後如果是我們去判斷Tag是不是我們的標記,是那就直接return true 意思就是見到了就直接返回一個讓ViewPager不要管,好了這個問
題就算是解決完成了。 在這裏可能有小夥伴想要直接用的時候看的不太明白,感覺不是那麼剛好是LazyViewPager和RecycleView,就是這樣的,這兩個只是我在這裏用的是 ,但是看明白之後都是這個原理,RecycleView這個
可以用任何的控件代替,因爲你只要在方法裏邊找到他就行了,而LazyViewPager這個,仔細想這個控件和ViewPager是通着的,所以想要這樣用,可以借鑑一下LazyViewPager的事件分發方法然後去集成重寫一下這個方法就有了。

以上是一個菜鳥的個人見解,有好的看法歡迎評論 。先謝過了~~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章