pulltorefresh 刷新与 nestedscroll 冲突的解决办法

 pulltorefresh 用的是这个框架: com.handmark.pulltorefresh.library;

做到一个奇葩功能,就是要使用android material design中的滚动隐藏tab的和搜索框,但是刷新要的是pulltorefresh 刷新 ,列表使用的是recyclerview(recyclerview自带nestedscroll)!

布局大致这样:


    
     
     
        
       
        
    
    
    
    
    
      
	
要滚动隐藏的就是toobar 和 searchview,viewpager加载的是几个pulltorefresh

然后,让我头疼了整整一下午的事情发生了,下拉刷新和上拉加载的时候,要滚动隐藏的部分一直都会和pulltorefresh拖动刷新冲突,也就是,无法完全滚动隐藏需要隐藏的tab.

试了n次后无果,只能查看通过寻根问底了,查看代码:

pulltorefresh中处理上拉刷新的关键代码如下:

switch (event.getAction()) {
			case MotionEvent.ACTION_MOVE: {
				final int activePointerIndex = MotionEventCompat.findPointerIndex(event,
                        mActivedPointerId);
				
				 if (activePointerIndex == -1) {
					 Log.d(LOG_TAG, "Invalid pointerId=" + mActivedPointerId + " in onTouchEvent");
	                    break;
	                }
				 
	                if (mIsBeingDragged) {
    					mLastMotionY = event.getY();
    					mLastMotionX = event.getX();
    					pullEvent();
    				}
				 
				
				break;
			}


			case MotionEvent.ACTION_DOWN: {
				if (isReadyForPull()) {
					mLastMotionY = mInitialMotionY = event.getY();
					mLastMotionX = mInitialMotionX = event.getX();
					return true;
				}
				mActivedPointerId = MotionEventCompat.getPointerId(event, 0);
				break;
			}


			case MotionEvent.ACTION_CANCEL:
			case MotionEvent.ACTION_UP: {
				if (mIsBeingDragged) {
					mIsBeingDragged = false;


					if (mState == State.RELEASE_TO_REFRESH
							&& (null != mOnRefreshListener || null != mOnRefreshListener2)) {
							setState(State.REFRESHING, true);
						return true;
					}


					// If we're already refreshing, just scroll back to the top
					if (isRefreshing()) {
						smoothScrollTo(0);
						return true;
					}


					// If we haven't returned by here, then we're not in a state
					// to pull, so just reset
					setState(State.RESET);


					return true;
				}
				break;
			}
		}


		return false;
	}
就是在ontouchEvent()事件当中进行操作。

下面来看实现recyclerview nestedScroll 的关键代码:

  case MotionEvent.ACTION_MOVE: {
                final int index = MotionEventCompat.findPointerIndex(e, mScrollPointerId);
                if (index < 0) {
                    Log.e(TAG, "Error processing scroll; pointer index for id " +
                            mScrollPointerId + " not found. Did any MotionEvents get skipped?");
                    return false;
                }

                final int x = (int) (MotionEventCompat.getX(e, index) + 0.5f);
                final int y = (int) (MotionEventCompat.getY(e, index) + 0.5f);
                int dx = mLastTouchX - x;
                int dy = mLastTouchY - y;

                if (dispatchNestedPreScroll(dx, dy, mScrollConsumed, mScrollOffset)) {
                    dx -= mScrollConsumed[0];
                    dy -= mScrollConsumed[1];
                    vtev.offsetLocation(mScrollOffset[0], mScrollOffset[1]);
                    // Updated the nested offsets
                    mNestedOffsets[0] += mScrollOffset[0];
                    mNestedOffsets[1] += mScrollOffset[1];
                }

                if (mScrollState != SCROLL_STATE_DRAGGING) {
                    boolean startScroll = false;
                    if (canScrollHorizontally && Math.abs(dx) > mTouchSlop) {
                        if (dx > 0) {
                            dx -= mTouchSlop;
                        } else {
                            dx += mTouchSlop;
                        }
                        startScroll = true;
                    }
                    if (canScrollVertically && Math.abs(dy) > mTouchSlop) {
                        if (dy > 0) {
                            dy -= mTouchSlop;
                        } else {
                            dy += mTouchSlop;
                        }
                        startScroll = true;
                    }
                    if (startScroll) {
                        setScrollState(SCROLL_STATE_DRAGGING);
                    }
                }

                if (mScrollState == SCROLL_STATE_DRAGGING) {
                    mLastTouchX = x - mScrollOffset[0];
                    mLastTouchY = y - mScrollOffset[1];

                    if (scrollByInternal(
                            canScrollHorizontally ? dx : 0,
                            canScrollVertically ? dy : 0,
                            vtev)) {
                        getParent().requestDisallowInterceptTouchEvent(true);
                    }
                }
            } break;
也是在ontouchEvent()事件当中进行的,但是注意关键方法
 
  
dispatchNestedPreScroll(dx, dy, mScrollConsumed, mScrollOffset);
这个方法就是告诉nestedScrollParent,赶紧滚动你该滚动的东西,滚动了多少在mScrollConsumed里告诉我。我也要滚。然后关键的地方就是,在recyclerview滚完后,事件回传给他的parent 也就是 pulltorefreshBase的ontouchEvent,此时pulltorefreshBase 接收到move后根本就不知道要隐藏的view有没有隐藏了,就开始执行
pullEvent();
然后,得到的结果就是他开始截断事件传递,不给recyclerview,然后自己去执行拖动刷新。那么,怎么让他知道要滚动的view有没有滚动结束呢?

那么来看pulltoreftreshbase里面的这个方法:

private boolean isReadyForPull() {
		switch (mMode) {
			case PULL_FROM_START:
				return isReadyForPullStart();
			case PULL_FROM_END:
				return isReadyForPullEnd();
			case BOTH:
				return isReadyForPullEnd() || isReadyForPullStart();
			default:
				return false;
		}
	}
这个方法就是询问是否可以开始拖动刷新啦。如果没有准备好,那我就不去实行拖动刷新。那么,要知道滚动刷新何时完成要的是
mScrollConsumed
这个参数,如果这个mScrollConsumed[1] = 0,那么说明已经要滚动的view已经完成滚动了。可以开始拖动刷新,那么在判断
sReadyForPullStart()

isReadyForPullEnd()
的时候加入这个判断就行了,由于这个是个静态方法,那只能去反射判断了,在pulltorefreshbase的继承类里面加上

代码:

@Override
    protected boolean isReadyForPullStart() {
    	int[] scrollconsumed = getNestedScrollConsumed();
    	if(scrollconsumed[1] != 0){
    		return false;
    	}
        if (mRefreshableView.getChildCount() <= 0)
            return true;
		int firstVisiblePosition = mRefreshableView.getChildAdapterPosition(mRefreshableView.getChildAt(0));
        if (firstVisiblePosition == 0)
            return mRefreshableView.getChildAt(0).getTop() == mRefreshableView.getPaddingTop();
        else
            return false;

    }

    @Override
    protected boolean isReadyForPullEnd() {
    	int[] scrollconsumed = getNestedScrollConsumed();
    	if(scrollconsumed[1] != 0){
    		return false;
    	}
    	if(mRefreshableView.getChildCount() <= 0){
    		return true;
    	}
		int lastVisiblePosition = mRefreshableView.getChildAdapterPosition(mRefreshableView.getChildAt(mRefreshableView.getChildCount() -1));
        if (lastVisiblePosition >= mRefreshableView.getAdapter().getItemCount()-1) {
            return mRefreshableView.getChildAt(mRefreshableView.getChildCount() - 1).getBottom() <= mRefreshableView.getBottom();
        }
        return false;
    }
    
    
    private int[] getNestedScrollConsumed(){
    	int[] consumed = new int[2];
    	try {
			Field field = RecyclerView.class.getDeclaredField("mScrollConsumed");
			if(field != null){
				field.setAccessible(true);
				consumed = (int[]) field.get(mRefreshableView);
				return consumed;
			}
			return consumed;
			
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	return consumed;
    	
    }




你可能感兴趣的:(pulltorefresh 刷新与 nestedscroll 冲突的解决办法)