SnapHelper 的详解可以参考这篇文章。
SnapHelper 是一个抽象类,官方提供了一个 LinearSnapHelper 的子类,可以让 RecyclerView 滚动停止时相应的 Item 停留中间位置。但是如果想让 Item 不居中对齐,而是左端或者右端对齐的话,就需要重新实现了。下面将实现一个端对齐的类。
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.LinearSnapHelper;
import androidx.recyclerview.widget.OrientationHelper;
import androidx.recyclerview.widget.RecyclerView;
public class SideAlignSnapHelper extends LinearSnapHelper {
private OrientationHelper helper;
private RecyclerView mRecyclerView;
private boolean mReverse = false;
@Override
public void attachToRecyclerView(@Nullable RecyclerView recyclerView) throws IllegalStateException {
super.attachToRecyclerView(recyclerView);
this.mRecyclerView = recyclerView;
RecyclerView.LayoutManager layoutManager = null;
if (mRecyclerView != null) {
layoutManager = mRecyclerView.getLayoutManager();
}
if (layoutManager instanceof LinearLayoutManager) {
mReverse = ((LinearLayoutManager) layoutManager).getReverseLayout();
}
}
private OrientationHelper getHelper(RecyclerView.LayoutManager layoutManager) {
if (helper == null) {
helper = OrientationHelper.createHorizontalHelper(layoutManager);
}
return helper;
}
@Override
public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) {
int[] out = new int[2];
if (layoutManager.canScrollHorizontally()) {
out[0] = distanceToStart(targetView, getHelper(layoutManager));
} else {
out[0] = 0;
}
return out;
}
private int distanceToStart(View targetView, OrientationHelper helper) {
int distance = 0;
if (mReverse) {
distance = helper.getDecoratedEnd(targetView) - helper.getEndAfterPadding();
} else {
distance = helper.getDecoratedStart(targetView) - helper.getStartAfterPadding();
}
return distance;
}
@Override
public View findSnapView(RecyclerView.LayoutManager layoutManager) {
return findStartView(layoutManager, getHelper(layoutManager));
}
private View findStartView(RecyclerView.LayoutManager layoutManager, OrientationHelper helper) {
int firstChild = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
int lastChild = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
if (firstChild == RecyclerView.NO_POSITION) {
return null;
}
View firstChildView = layoutManager.findViewByPosition(firstChild);
View lastChildView = layoutManager.findViewByPosition(lastChild);
int start = 0, end = 0;
if (mReverse) {
start = Math.abs(helper.getTotalSpace() - helper.getDecoratedStart(firstChildView));
end = helper.getDecoratedEnd(lastChildView);
} else {
start = helper.getDecoratedEnd(firstChildView);
end = Math.abs(helper.getDecoratedStart(lastChildView) - helper.getTotalSpace());
}
if (start >= end) {
return firstChildView;
} else {
return layoutManager.findViewByPosition(firstChild + 1);
}
}
}
重写 findSnapView 方法以及 calculateDistanceToFinalSnap 方法。
注意需要根据 LinearLayoutManager.getReverseLayout 的方向判断对齐方向。
如下图: