先写引用 侵删
https://www.jianshu.com/p/e54db232df62
https://www.jianshu.com/p/9b8e0696802d
/**
* Created by Administrator (chenPS) on 2020/3/4.
*/
public class LeftSnapHelper extends SnapHelper {
// Orientation helpers are lazily created per LayoutManager.
@Nullable
private OrientationHelper mVerticalHelper;
@Nullable
private OrientationHelper mHorizontalHelper;
@Nullable
@Override
public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) {
Log.w("LeftSnapHelper", "calculateDistanceToFinalSnap");
int out[] = new int[2];
if (layoutManager.canScrollHorizontally()) {
out[0] = distanceToEnd(targetView, getHorizontalHelper(layoutManager));
} else {
out[0] = 0;
}
return out;
}
//targetView的start坐标与RecyclerView的paddingStart之间的差值
//就是需要滚动调整的距离
private int distanceToStart(View targetView, OrientationHelper helper) {
return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding();
}
private int distanceToEnd(View targetView, OrientationHelper helper) {
Log.v("test",helper.getEndAfterPadding()+" === "+helper.getDecoratedEnd(targetView));
return -helper.getEndAfterPadding() + helper.getDecoratedEnd(targetView);
}
/**
* 该方法会找到当前layoutManager上最接近对齐位置的那个view,
* 该view称为SanpView,对应的position称为SnapPosition。
* 如果返回null,就表示没有需要对齐的View,也就不会做滚动对齐调整。
*/
@Nullable
@Override
public View findSnapView(RecyclerView.LayoutManager layoutManager) {
Log.w("LeftSnapHelper", "findSnapView");
return findEndView(layoutManager, getHorizontalHelper(layoutManager));
}
private View findEndView(RecyclerView.LayoutManager layoutManager, OrientationHelper helper) {
if (!layoutManager.canScrollHorizontally()) {
return null;
}
if (layoutManager instanceof LinearLayoutManager) {
int lastItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
View view = layoutManager.findViewByPosition(lastItemPosition);
if(view==null){
return null;
}
int itemWidth = helper.getDecoratedMeasurement(view)/2;
Log.v("test",itemWidth+" item 的宽度");
int invisiableWidth =helper.getDecoratedEnd(view)-helper.getEnd();
Log.v("test",invisiableWidth+" ");
if (invisiableWidth < itemWidth) {
return view;
} else {
return layoutManager.findViewByPosition(lastItemPosition - 1);
}
}
return null;
}
private View findStartView(RecyclerView.LayoutManager layoutManager, OrientationHelper helper) {
if (layoutManager instanceof LinearLayoutManager) {
int firstChildPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
if (firstChildPosition == RecyclerView.NO_POSITION) {
return null;
}
//找到最后一个完全显示的ItemView,如果该ItemView是列表中的最后一个
//就说明列表已经滑动最后了,这时候就不应该根据第一个ItemView来对齐了
//要不然由于需要跟第一个ItemView对齐最后一个ItemView可能就一直无法完全显示,
//所以这时候直接返回null表示不需要对齐
if (((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition() == layoutManager.getItemCount() - 1) {
return null;
}
View firstChildView = layoutManager.findViewByPosition(firstChildPosition);
if (helper.getDecoratedEnd(firstChildView) >= helper.getDecoratedMeasurement(firstChildView) / 2
&& helper.getDecoratedEnd(firstChildView) > 0) {
return firstChildView;
} else {
return layoutManager.findViewByPosition(firstChildPosition + 1);
}
} else {
return null;
}
}
//在触发fling时找到targetSnapPosition。
@Override
public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
Log.e("LeftSnapHelper", "findTargetSnapPosition");
if (!(layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) {
return -1;
}
int itemCount = layoutManager.getItemCount();
if (itemCount == 0) {
return -1;
}
View currentView = findSnapView(layoutManager);
if (currentView == null) {
return -1;
}
int currentPosition = layoutManager.getPosition(currentView);
if (currentPosition == -1) {
return -1;
}
RecyclerView.SmoothScroller.ScrollVectorProvider vectorProvider = (RecyclerView.SmoothScroller.ScrollVectorProvider) layoutManager;
PointF vectorForEnd = vectorProvider.computeScrollVectorForPosition(itemCount - 1);
if (vectorForEnd == null) {
return -1;
}
int deltaThreshold = layoutManager.getWidth() / getHorizontalHelper(layoutManager).getDecoratedMeasurement(currentView);
int deltaJump;
if (layoutManager.canScrollHorizontally()) {
deltaJump = estimateNextPositionDiffForFling(layoutManager, getHorizontalHelper(layoutManager), velocityX, 0);
if (deltaJump > deltaThreshold) {
deltaJump = deltaThreshold;
}
if (deltaJump < -deltaThreshold) {
deltaJump = -deltaThreshold;
}
if (vectorForEnd.x < 0) {
deltaJump = -deltaJump;
}
} else {
deltaJump = 0;
}
if (deltaJump == 0) {
return -1;
}
int targetPos = currentPosition + deltaJump;
if (targetPos < 0) {
targetPos = 0;
}
if (targetPos >= itemCount) {
targetPos = itemCount - 1;
}
return targetPos;
}
@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;
}
private int estimateNextPositionDiffForFling(RecyclerView.LayoutManager layoutManager,
OrientationHelper helper, int velocityX, int velocityY) {
int[] distances = calculateScrollDistance(velocityX, velocityY);
float distancePerChild = computeDistancePerChild(layoutManager, helper);
if (distancePerChild <= 0) {
return 0;
}
int distance =
Math.abs(distances[0]) > Math.abs(distances[1]) ? distances[0] : distances[1];
return (int) Math.round(distance / distancePerChild);
}
private float computeDistancePerChild(RecyclerView.LayoutManager layoutManager,
OrientationHelper helper) {
View minPosView = null;
View maxPosView = null;
int minPos = Integer.MAX_VALUE;
int maxPos = Integer.MIN_VALUE;
int childCount = layoutManager.getChildCount();
if (childCount == 0) {
return 1f;
}
for (int i = 0; i < childCount; i++) {
View child = layoutManager.getChildAt(i);
final int pos = layoutManager.getPosition(child);
if (pos == RecyclerView.NO_POSITION) {
continue;
}
if (pos < minPos) {
minPos = pos;
minPosView = child;
}
if (pos > maxPos) {
maxPos = pos;
maxPosView = child;
}
}
if (minPosView == null || maxPosView == null) {
return 1f;
}
int start = Math.min(helper.getDecoratedStart(minPosView),
helper.getDecoratedStart(maxPosView));
int end = Math.max(helper.getDecoratedEnd(minPosView),
helper.getDecoratedEnd(maxPosView));
int distance = end - start;
if (distance == 0) {
return 1f;
}
return 1f * distance / ((maxPos - minPos) + 1);
}
@Nullable
@Override
protected LinearSmoothScroller createSnapScroller(RecyclerView.LayoutManager layoutManager) {
return super.createSnapScroller(layoutManager);
}
}