本效果基于SnapHelper的源碼的基礎(chǔ)上進(jìn)行修改蛙埂,區(qū)分處理了onFiling事件和onScroll事件:
ezgif.com-video-to-gif.gif
上代碼:
private final RecyclerView.OnScrollListener mScrollListener = new RecyclerView.OnScrollListener() {
boolean mScrolled = false;
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
// SCROLL_STATE_IDLE是當(dāng)屏幕停止?jié)L動(dòng)時(shí) 0
//SCROLL_STATE_TOUCH_SCROLL是當(dāng)用戶在以觸屏方式滾動(dòng)屏幕并且手指仍然還在屏幕上時(shí) 1
//SCROLL_STATE_FLING是當(dāng)用戶由于之前劃動(dòng)屏幕并抬起手指,屏幕產(chǎn)生慣性滑動(dòng)時(shí) 2
if (newState != RecyclerView.SCROLL_STATE_IDLE) {
return;
}
//當(dāng)滾動(dòng)停止且產(chǎn)生位移的時(shí)候執(zhí)行對(duì)齊方法
if (mScrolled) {
mScrolled = false;
snapToTargetExistingView();
return;
}
//當(dāng)不在位移的時(shí)候?qū)?dāng)前的位置提供出來
if (mPageListener != null) {
mPageListener.onPageSelector(mCurrentPageIndex);
}
}
Scroll事件的處理邏輯
/**
* 獲取當(dāng)前應(yīng)該顯示第幾頁
*/
private int getPagerIndex() {
final int verticalScrollOffset = mRecyclerView.computeVerticalScrollOffset();
final int horizontalScrollOffset = mRecyclerView.computeHorizontalScrollOffset();
final int currentVerticalScrollOffset = mCurrentPageIndex * mRecyclerView.getMeasuredHeight();
final int currentHorizontalScrollOffset = mCurrentPageIndex * mRecyclerView.getMeasuredWidth();
int index = 0;
if (mRecyclerView.getLayoutManager().canScrollVertically()) {
//除掉整頁距離之后的距離
final float offset = verticalScrollOffset * 1.f % mRecyclerView.getMeasuredHeight();
final float page = verticalScrollOffset * 1.f / mRecyclerView.getMeasuredHeight();//前面還有多少頁
index = (int) Math.floor(page);//前面還有多少頁, 取整
if (offset == 0) {
return index;
}
if (currentVerticalScrollOffset <= verticalScrollOffset) {
//向上滾動(dòng)
if (offset >= mRecyclerView.getMeasuredHeight() / 2) {
//超過屏幕 1/2 就開始滑動(dòng)
index = mCurrentPageIndex + 1;
} else {
index = mCurrentPageIndex;
}
} else {
//向下滾動(dòng)
if (offset >= mRecyclerView.getMeasuredHeight() / 2) {
//超過屏幕 1/2 就開始滑動(dòng)
index = mCurrentPageIndex;
} else {
index = mCurrentPageIndex - 1;
}
}
} else if (mRecyclerView.getLayoutManager().canScrollHorizontally()) {
final float offset = horizontalScrollOffset * 1.f % mRecyclerView.getMeasuredWidth();
final float page = horizontalScrollOffset * 1.f / mRecyclerView.getMeasuredWidth();
index = (int) Math.floor(page);
if (offset == 0) {
return index;
}
if (currentHorizontalScrollOffset <= horizontalScrollOffset) {
//向左滾動(dòng)
if (offset >= mRecyclerView.getMeasuredWidth() / 2) {
//超過一半的距離
index = mCurrentPageIndex + 1;
} else {
index = mCurrentPageIndex;
}
} else {
//向右滾動(dòng)
if (offset >= mRecyclerView.getMeasuredWidth() / 2) {
//超過一半的距離
index = mCurrentPageIndex;
} else {
index = mCurrentPageIndex - 1;
}
}
}
return index;
}
fling事件的處理邏輯
/**
* 當(dāng)fling事件執(zhí)行后找到fling最終的position
*
* @param layoutManager
* @param velocityX
* @param velocityY
* @return
*/
private int findTargetSnapPosition(LayoutManager layoutManager, int velocityX, int velocityY) {
final int itemCount = layoutManager.getItemCount();
if (itemCount == 0) {
return RecyclerView.NO_POSITION;
}
int index = RecyclerView.NO_POSITION;
if (layoutManager.canScrollHorizontally()) {
if (velocityX > 0) {
return mCurrentPageIndex + 1;
} else {
return mCurrentPageIndex - 1;
}
}
if (layoutManager.canScrollVertically()) {
if (velocityY > 0) {
return mCurrentPageIndex + 1;
} else {
return mCurrentPageIndex - 1;
}
}
return index;
}
最終snap邏輯:
/**
* 滑動(dòng)事件的真正執(zhí)行
*
* @param layoutManager
* @param position
*/
private void handleScrollToPosition(LayoutManager layoutManager, int position) {
int itemCount = layoutManager.getItemCount();
if (itemCount == 0) {
return;
}
if (position >= itemCount) {
return;
}
mCurrentPageIndex = position;
int[] snapDistance = calculateDistanceToFinalSnap(layoutManager);
if (snapDistance[0] != 0 || snapDistance[1] != 0) {
mRecyclerView.smoothScrollBy(snapDistance[0], snapDistance[1]);
}
}
計(jì)算真正需要滑動(dòng)的距離:
@SuppressWarnings("WeakerAccess")
@Nullable
public int[] calculateDistanceToFinalSnap(@NonNull LayoutManager layoutManager) {
int[] out = new int[2];
if (layoutManager.canScrollHorizontally()) {
out[0] = mCurrentPageIndex * mRecyclerView.getMeasuredWidth() - mRecyclerView.computeHorizontalScrollOffset();
} else {
out[0] = 0;
}
if (layoutManager.canScrollVertically()) {
out[1] = mCurrentPageIndex * mRecyclerView.getMeasuredHeight() - mRecyclerView.computeVerticalScrollOffset();
} else {
out[1] = 0;
}
return out;
}