SnapHelper是support-v7:24.2.0新增的,用於控制RecyclerView滑動停止後Item的對齊方式。默認提供了兩種對齊方式PagerSnapHelper 與 LinearSnapHelper。PagerSnapHelper 和ViewPage效果一樣,一次滑動一頁。LinearSnapHelper這是Item居中對齊。使用方式非常簡單:
PagerSnapHelper mPagerSnapHelper = new PagerSnapHelper();
mPagerSnapHelper.attachToRecyclerView(mRecyclerView);
效果如下
當然我們可以自定義SnapHelper,來實現我們想要的對齊方式,下面我們來實現一下左對齊。
public class MySnapHelper extends LinearSnapHelper{
/**
* 水平、垂直方向的度量
*/
@Nullable
private OrientationHelper mVerticalHelper;
@Nullable
private OrientationHelper mHorizontalHelper;
@NonNull
private OrientationHelper getVerticalHelper(@NonNull RecyclerView.LayoutManager layoutManager) {
if (mVerticalHelper == null) {
mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager);
}
return mVerticalHelper;
}
@NonNull
private OrientationHelper getHorizontalHelper(@NonNull RecyclerView.LayoutManager layoutManager) {
if (mHorizontalHelper == null) {
mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
}
return mHorizontalHelper;
}
/**
* 計算出View對齊到指定位置,所需的x、y軸上的偏移量。
*/
@Nullable
@Override
public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) {
int[] out = new int[2];
// 水平方向滑動時計算x方向,否則偏移爲0
if (layoutManager.canScrollHorizontally()) {
out[0] = distanceToStart(layoutManager, targetView, getHorizontalHelper(layoutManager));
} else {
out[0] = 0;
}
// 垂直方向滑動時計算y方向,否則偏移爲0
if (layoutManager.canScrollVertically()) {
out[1] = distanceToStart(layoutManager, targetView, getVerticalHelper(layoutManager));
} else {
out[1] = 0;
}
return out;
}
private int distanceToStart(RecyclerView.LayoutManager layoutManager, View targetView, OrientationHelper helper) {
// RecyclerView的邊界x值,也就是左側Padding值
final int start;
if (layoutManager.getClipToPadding()) {
start = helper.getStartAfterPadding();
} else {
start = 0;
}
return helper.getDecoratedStart(targetView) - start;
}
/**
* 查找需要對齊的View
*/
@Nullable
@Override
public View findSnapView(RecyclerView.LayoutManager layoutManager) {
if (layoutManager.canScrollVertically()) {
return findStartView(layoutManager, getVerticalHelper(layoutManager));
} else {
return findStartView(layoutManager, getHorizontalHelper(layoutManager));
}
}
private View findStartView(RecyclerView.LayoutManager layoutManager, OrientationHelper helper) {
int childCount = layoutManager.getChildCount();
if (childCount == 0) {
return null;
}
View closestChild = null;
final int start;
if (layoutManager.getClipToPadding()) {
start = helper.getStartAfterPadding();
} else {
start = 0;
}
int absClosest = Integer.MAX_VALUE;
for (int i = 0; i < childCount; i++) {
final View child = layoutManager.getChildAt(i);
// ItemView 的左側座標
int childStart = helper.getDecoratedStart(child);
// 計算此ItemView 與 RecyclerView左側的距離
int absDistance = Math.abs(childStart - start);
// 找到那個最靠近左側的ItemView然後返回
if (absDistance < absClosest) {
absClosest = absDistance;
closestChild = child;
}
}
return closestChild;
}
/**
* 找到需要對齊的View的position,主要用於fling 操作
*/
@Override
public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
// 左對齊和居中對齊一樣,無需自定義處理
return super.findTargetSnapPosition(layoutManager, velocityX, velocityY);
}
}
上面的註釋已將關鍵地方註明,效果我就不展示了。大家可以下載代碼去體驗。本篇所有代碼已上傳至Github。
轉自:https://blog.csdn.net/qq_17766199/article/details/83147483