实现功能:在网格布局下(GridLayoutManager),实现横向滚动,多行多列,分页滚动效果
1.重写SnapHelper类
import android.graphics.PointF;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearSmoothScroller;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.LayoutManager;
import android.support.v7.widget.RecyclerView.State;
import android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider;
import android.support.v7.widget.SnapHelper;
import android.util.DisplayMetrics;
import android.view.View;
/**
* Created by Muyuki on 2019/11/8
* 网格布局分页效果
* 仅限布局为GridLayoutManager使用
*/
public class GridPagerSnapHelper extends SnapHelper {
@Nullable
private OrientationHelper mVerticalHelper;
@Nullable
private OrientationHelper mHorizontalHelper;
private RecyclerView recyclerView;
private int rowCount = 1;
private int columCount = 1;
/**
* @param row 行
* @param column 列
*/
public GridPagerSnapHelper(int row,int column) {
this.rowCount = row;
this.columCount = column;
}
@Override
public void attachToRecyclerView(@Nullable RecyclerView recyclerView) throws IllegalStateException {
super.attachToRecyclerView(recyclerView);
this.recyclerView = recyclerView;
}
@Nullable
@Override
public int[] calculateDistanceToFinalSnap(@NonNull LayoutManager layoutManager, @NonNull View targetView) {
int[] out = new int[2];
if (layoutManager.canScrollHorizontally()) {
out[0] = this.distanceToStart(layoutManager, targetView, this.getHorizontalHelper(layoutManager));
} else {
out[0] = 0;
}
if (layoutManager.canScrollVertically()) {
out[1] = this.distanceToStart(layoutManager, targetView, this.getVerticalHelper(layoutManager));
} else {
out[1] = 0;
}
return out;
}
@Nullable
@Override
public View findSnapView(LayoutManager layoutManager) {
if (layoutManager.canScrollVertically()) {
return this.findStartSnapView(layoutManager, this.getVerticalHelper(layoutManager));
} else {
return layoutManager.canScrollHorizontally() ? this.findStartSnapView(layoutManager, this.getHorizontalHelper(layoutManager)) : null;
}
}
@Override
public int findTargetSnapPosition(LayoutManager layoutManager, int velocityX, int velocityY) {
int itemCount = layoutManager.getItemCount();
if (itemCount == 0) {
return -1;
} else {
View mStartMostChildView = null;
if (layoutManager.canScrollVertically()) {
mStartMostChildView = this.findStartView(layoutManager, this.getVerticalHelper(layoutManager));
} else if (layoutManager.canScrollHorizontally()) {
mStartMostChildView = this.findStartView(layoutManager, this.getHorizontalHelper(layoutManager));
}
if (mStartMostChildView == null) {
return -1;
} else {
int centerPosition = layoutManager.getPosition(mStartMostChildView);
if (centerPosition == -1) {
return -1;
} else {
// 计算当前页面索引
int pagerIndex = centerPosition / (rowCount * columCount);
// 是否滑向下一页
boolean forwardDirection;
if (layoutManager.canScrollHorizontally()) {
forwardDirection = velocityX > 0;
} else {
forwardDirection = velocityY > 0;
}
// 条目是否是翻转模式
boolean reverseLayout = false;
if (layoutManager instanceof ScrollVectorProvider) {
ScrollVectorProvider vectorProvider = (ScrollVectorProvider) layoutManager;
PointF vectorForEnd = vectorProvider.computeScrollVectorForPosition(itemCount - 1);
if (vectorForEnd != null) {
reverseLayout = vectorForEnd.x < 0.0F || vectorForEnd.y < 0.0F;
}
}
int targetPosition = -1;
if (reverseLayout) {
targetPosition = (forwardDirection ? (pagerIndex - 1) * (rowCount * columCount) : (pagerIndex) * (rowCount * columCount));
} else {
targetPosition = (forwardDirection ? (pagerIndex + 1) * (rowCount * columCount) : (pagerIndex) * (rowCount * columCount));
}
return targetPosition;
}
}
}
}
@Override
protected LinearSmoothScroller createSnapScroller(LayoutManager layoutManager) {
return !(layoutManager instanceof ScrollVectorProvider) ? null : new LinearSmoothScroller(this.recyclerView.getContext()) {
protected void onTargetFound(View targetView, State state, Action action) {
int[] snapDistances = GridPagerSnapHelper.this.calculateDistanceToFinalSnap(GridPagerSnapHelper.this.recyclerView.getLayoutManager(), targetView);
int dx = snapDistances[0];
int dy = snapDistances[1];
int time = this.calculateTimeForDeceleration(Math.max(Math.abs(dx), Math.abs(dy)));
if (time > 0) {
action.update(dx, dy, time, this.mDecelerateInterpolator);
}
}
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return 100.0F / (float) displayMetrics.densityDpi;
}
protected int calculateTimeForScrolling(int dx) {
return Math.min(100, super.calculateTimeForScrolling(dx));
}
};
}
private int distanceToStart(@NonNull LayoutManager layoutManager, @NonNull View targetView, OrientationHelper helper) {
int childStart = helper.getDecoratedStart(targetView);
int containerStart;
if (layoutManager.getClipToPadding()) {
containerStart = helper.getStartAfterPadding();
} else {
containerStart = 0;
}
return childStart - containerStart;
}
@Nullable
private View findStartSnapView(LayoutManager layoutManager, OrientationHelper helper) {
int childCount = layoutManager.getChildCount();
if (childCount == 0) {
return null;
} else {
View closestChild = null;
int start;
if (layoutManager.getClipToPadding()) {
start = helper.getStartAfterPadding();
} else {
start = 0;
}
int absClosest = 2147483647;
for (int i = 0; i < childCount; ++i) {
View child = layoutManager.getChildAt(i);
int childStart = helper.getDecoratedStart(child);
int absDistance = Math.abs(childStart - start);
if (absDistance < absClosest) {
absClosest = absDistance;
closestChild = child;
}
}
return closestChild;
}
}
@Nullable
private View findStartView(LayoutManager layoutManager, OrientationHelper helper) {
int childCount = layoutManager.getChildCount();
if (childCount == 0) {
return null;
} else {
View closestChild = null;
int startest = 2147483647;
for (int i = 0; i < childCount; ++i) {
View child = layoutManager.getChildAt(i);
int childStart = helper.getDecoratedStart(child);
if (childStart < startest) {
startest = childStart;
closestChild = child;
}
}
return closestChild;
}
}
@NonNull
private OrientationHelper getVerticalHelper(@NonNull LayoutManager layoutManager) {
if (this.mVerticalHelper == null || this.mVerticalHelper.getLayoutManager() != layoutManager) {
this.mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager);
}
return this.mVerticalHelper;
}
@NonNull
private OrientationHelper getHorizontalHelper(@NonNull LayoutManager layoutManager) {
if (this.mHorizontalHelper == null || this.mHorizontalHelper.getLayoutManager() != layoutManager) {
this.mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
}
return this.mHorizontalHelper;
}
}
2.使用方法
//横向列表 3行
GridLayoutManager gridLayoutManager=new GridLayoutManager(context, 3,LinearLayoutManager.HORIZONTAL, false);
recycler.setLayoutManager(gridLayoutManager);
homeAdapter=new HomeAdapter();
//3行,1列
new GridPagerSnapHelper(3,1).attachToRecyclerView(recycler);
recycler.setAdapter(homeAdapter);