pulltorefresh 用的是这个框架: com.handmark.pulltorefresh.library;
布局大致这样:
要滚动隐藏的就是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;
}