您的位置:首页 > 其它

ItemTouchHelper源码分析 拖拽到屏幕边缘的处理

2017-07-03 20:17 411 查看
如果列表被拖拉到屏幕边缘 该runnable会被递归调用 

/**
* When user drags a view to the edge, we start scrolling the LayoutManager as long as View
* is partially out of bounds.
*/
final Runnable mScrollRunnable = new Runnable() {
@Override
public void run() {
if (mSelected != null && scrollIfNecessary()) {
if (mSelected != null) { //it might be lost during scrolling
moveIfNecessary(mSelected);
}
mRecyclerView.removeCallbacks(mScrollRunnable);
ViewCompat.postOnAnimation(mRecyclerView, this);
}
}
};

ViewCompat.postOnAnimation()实际调用了view.postOnAnimation
下面是调用的方法栈:

static final ViewCompatImpl IMPL;
static {
final int version = android.os.Build.VERSION.SDK_INT;
if (BuildCompat.isAtLeastN()) {
IMPL = new Api24ViewCompatImpl();
} else if (version >= 23) {
IMPL = new MarshmallowViewCompatImpl();
} else if (version >= 21) {
IMPL = new LollipopViewCompatImpl();
} else if (version >= 19) {
IMPL = new KitKatViewCompatImpl();
} else if (version >= 18) {
IMPL = new JbMr2ViewCompatImpl();
} else if (version >= 17) {
IMPL = new JbMr1ViewCompatImpl();
} else if (version >= 16) {
IMPL = new JBViewCompatImpl(); //在这里实现
} else if (version >= 15) {
IMPL = new ICSMr1ViewCompatImpl();
} else if (version >= 14) {
IMPL = new ICSViewCompatImpl();
} else if (version >= 11) {
IMPL = new HCViewCompatImpl();
} else {
IMPL = new BaseViewCompatImpl();
}
}

static class JBViewCompatImpl extends ICSMr1ViewCompatImpl {
@Override
public boolean hasTransientState(View view) {
return ViewCompatJB.hasTransientState(view);
}
@Override
public void setHasTransientState(View view, boolean hasTransientState) {
ViewCompatJB.setHasTransientState(view, hasTransientState);
}
@Override
public void postInvalidateOnAnimation(View view) {
ViewCompatJB.postInvalidateOnAnimation(view);
}
@Override
public void postInvalidateOnAnimation(View view, int left, int top, int right, int bottom) {
ViewCompatJB.postInvalidateOnAnimation(view, left, top, right, bottom);
}
@Override
public void postOnAnimation(View view, Runnable action) {
ViewCompatJB.postOnAnimation(view, action);
}
class ViewCompatJB {

public static boolean hasTransientState(View view) {
return view.hasTransientState();
}

public static void setHasTransientState(View view, boolean hasTransientState) {
view.setHasTransientState(hasTransientState);
}

public static void postInvalidateOnAnimation(View view) {
view.postInvalidateOnAnimation();
}

public static void postInvalidateOnAnimation(View view, int left, int top,
int right, int bottom) {
view.postInvalidate(left, top, right, bottom);
}

public static void postOnAnimation(View view, Runnable action) {
view.postOnAnimation(action);
}


回来看scrollIfNecessary和moveIfNecessary方法
/**
* If user drags the view to the edge, trigger a scroll if necessary. 如果用户拖拽rv到边缘,必要的话将在这个方法内触发scrollby
*/
boolean scrollIfNecessary() {
if (mSelected == null) {
mDragScrollStartTimeInMs = Long.MIN_VALUE;
return false;
}
final long now = System.currentTimeMillis();
final long scrollDuration = mDragScrollStartTimeInMs
== Long.MIN_VALUE ? 0 : now - mDragScrollStartTimeInMs;
RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager();
if (mTmpRect == null) {
mTmpRect = new Rect();
}
int scrollX = 0;
int scrollY = 0;
lm.calculateItemDecorationsForChild(mSelected.itemView, mTmpRect);
if (lm.canScrollHorizontally()) {
int curX = (int) (mSelectedStartX + mDx);
final int leftDiff = curX - mTmpRect.left - mRecyclerView.getPaddingLeft();
if (mDx < 0 && leftDiff < 0) {
scrollX = leftDiff;
} else if (mDx > 0) {
final int rightDiff =
curX + mSelected.itemView.getWidth() + mTmpRect.right
- (mRecyclerView.getWidth() - mRecyclerView.getPaddingRight());
if (rightDiff > 0) {
scrollX = rightDiff;
}
}
}
if (lm.canScrollVertically()) {
int curY = (int) (mSelectedStartY + mDy);
final int topDiff = curY - mTmpRect.top - mRecyclerView.getPaddingTop();
if (mDy < 0 && topDiff < 0) {
scrollY = topDiff;
} else if (mDy > 0) {
final int bottomDiff = curY + mSelected.itemView.getHeight() + mTmpRect.bottom -
(mRecyclerView.getHeight() - mRecyclerView.getPaddingBottom());
if (bottomDiff > 0) {
scrollY = bottomDiff;
}
}
}
if (scrollX != 0) {
scrollX = mCallback.interpolateOutOfBoundsScroll(mRecyclerView,
mSelected.itemView.getWidth(), scrollX,
mRecyclerView.getWidth(), scrollDuration);
}
if (scrollY != 0) {
scrollY = mCallback.interpolateOutOfBoundsScroll(mRecyclerView,
mSelected.itemView.getHeight(), scrollY,
mRecyclerView.getHeight(), scrollDuration);
}
if (scrollX != 0 || scrollY != 0) {
if (mDragScrollStartTimeInMs == Long.MIN_VALUE) {
mDragScrollStartTimeInMs = now;
}
mRecyclerView.scrollBy(scrollX, scrollY);
return true;
}
mDragScrollStartTimeInMs = Long.MIN_VALUE;
return false;
}


mCallback.interpolateOutOfBoundsScroll 方法介绍
/**

         * Called by the ItemTouchHelper when user is dragging a view out of bounds.

         * <p>

         * You can override this method to decide how much RecyclerView should scroll in response

         * to this action. Default implementation calculates a value based on the amount of View

         * out of bounds and the time it spent there. The longer user keeps the View out of bounds,

         * the faster the list will scroll. Similarly, the larger portion of the View is out of

当用户界外拖动rv 被ItemTouchHelper调用。 返回值 计算应该滚动多少!

您可以重写此方法以决定RecyclerView响应这个动作时应该滚动多少。默认实现基于越界的View数量和它在那里花费的时间来计算一个值。用户将View拖拽在界外越久,列表将滚动得越快。同样,View的较大部分出界,RecyclerView将滚动得更快。

  

scrollIfNecessary 计算出scrollY之后 mRecyclerView调用scrollBy(scrollX, scrollY);  然后返回true 让moveIfNecessary再去决定是否要回调onMove或者onSwap
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: