Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
When set
GridLayoutManager
with spanCount is 1,
PagerSnapHelper
work the best.
But when set spanCount is 3,
PagerSnapHelper
has to scroll very hard.
How set
SnapHelper
scroll horizontal with
GridLayoutManger
with spanCount is 3.
PagerSnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(rvItemOriginalContent);
rvItemOriginalContent.setLayoutManager(new GridLayoutManager(context,
GridLayoutManager.HORIZONTAL,
false));
Can you help me, thanks you.
import android.graphics.PointF;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SnapHelper;
import android.view.View;
public class PagerSnapWithSpanCountHelper
extends SnapHelper {
private int mSpanCount;
private boolean mIsEnableCenter;
public PagerSnapWithSpanCountHelper(int mSpanCount,
boolean mIsEnableCenter) {
// spanCount always >=1
this.mSpanCount = mSpanCount;
this.mIsEnableCenter = mIsEnableCenter;
public PagerSnapWithSpanCountHelper(int mSpanCount) {
// spanCount always >=1
this.mSpanCount = mSpanCount;
// Orientation helpers are lazily created per LayoutManager.
@Nullable
private OrientationHelper mVerticalHelper;
@Nullable
private OrientationHelper mHorizontalHelper;
@Nullable
@Override
public int[] calculateDistanceToFinalSnap(
@NonNull final RecyclerView.LayoutManager layoutManager,
@NonNull final View targetView) {
int[] out = new int[2];
if (layoutManager.canScrollHorizontally()) {
out[0] = mIsEnableCenter ?
distanceToCenter(layoutManager,
targetView,
getHorizontalHelper(layoutManager)) :
distanceToStart(targetView,
getHorizontalHelper(layoutManager));
} else {
out[0] = 0;
if (layoutManager.canScrollVertically()) {
out[1] = mIsEnableCenter ?
distanceToCenter(layoutManager,
targetView,
getVerticalHelper(layoutManager)) :
distanceToStart(targetView,
getVerticalHelper(layoutManager));
} else {
out[1] = 0;
return out;
private View findStartView(RecyclerView.LayoutManager layoutManager,
OrientationHelper helper) {
if (layoutManager instanceof LinearLayoutManager) {
int firstChild = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
boolean isLastItem = ((LinearLayoutManager) layoutManager)
.findLastCompletelyVisibleItemPosition()
== layoutManager.getItemCount() - 1;
if (firstChild == RecyclerView.NO_POSITION || isLastItem) {
return null;
View child = layoutManager.findViewByPosition(firstChild);
if (helper.getDecoratedEnd(child) >= helper.getDecoratedMeasurement(child) / 2
&& helper.getDecoratedEnd(child) > 0) {
return child;
} else {
if (((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition()
== layoutManager.getItemCount() - 1) {
return null;
} else {
return layoutManager.findViewByPosition(firstChild + 1);
return findSnapView(layoutManager);
center item.
@Nullable
private View findCenterView(RecyclerView.LayoutManager layoutManager,
OrientationHelper helper) {
int childCount = layoutManager.getChildCount();
if (childCount == 0) {
return null;
View closestChild = null;
final int center;
if (layoutManager.getClipToPadding()) {
center = helper.getStartAfterPadding() + helper.getTotalSpace() / 2;
} else {
center = helper.getEnd() / 2;
int absClosest = Integer.MAX_VALUE;
for (int i = 0; i < childCount; i++) {
final View child = layoutManager.getChildAt(i);
int childCenter = helper.getDecoratedStart(child)
+ (helper.getDecoratedMeasurement(child) / 2);
int absDistance = Math.abs(childCenter - center);
if (absDistance < absClosest) {
absClosest = absDistance;
closestChild = child;
return closestChild;
@Nullable
@Override
public View findSnapView(final RecyclerView.LayoutManager layoutManager) {
if (layoutManager.canScrollVertically()) {
return mIsEnableCenter ?
findCenterView(layoutManager,
getVerticalHelper(layoutManager)) :
findStartView(layoutManager,
getVerticalHelper(layoutManager));
} else if (layoutManager.canScrollHorizontally()) {
return mIsEnableCenter ?
findCenterView(layoutManager,
getHorizontalHelper(layoutManager)) :
findStartView(layoutManager,
getHorizontalHelper(layoutManager));
return null;
@Override
public int findTargetSnapPosition(final RecyclerView.LayoutManager layoutManager,
final int velocityX,
final int velocityY) {
final int itemCount = layoutManager.getItemCount();
if (itemCount == 0) {
return RecyclerView.NO_POSITION;
View mStartMostChildView = null;
if (layoutManager.canScrollVertically()) {
mStartMostChildView = mIsEnableCenter ?
findCenterView(layoutManager,
getVerticalHelper(layoutManager)) :
findStartView(layoutManager,
getVerticalHelper(layoutManager));
} else if (layoutManager.canScrollHorizontally()) {
mStartMostChildView = mIsEnableCenter ?
findCenterView(layoutManager,
getHorizontalHelper(layoutManager)) :
findStartView(layoutManager,
getHorizontalHelper(layoutManager));
if (mStartMostChildView == null) {
return RecyclerView.NO_POSITION;
final int centerPosition = layoutManager.getPosition(mStartMostChildView);
if (centerPosition == RecyclerView.NO_POSITION) {
return RecyclerView.NO_POSITION;
final boolean forwardDirection;
if (layoutManager.canScrollHorizontally()) {
forwardDirection = velocityX > 0;
} else {
forwardDirection = velocityY > 0;
boolean reverseLayout = false;
if ((layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) {
RecyclerView.SmoothScroller.ScrollVectorProvider vectorProvider =
(RecyclerView.SmoothScroller.ScrollVectorProvider) layoutManager;
PointF vectorForEnd = vectorProvider.computeScrollVectorForPosition(itemCount - 1);
if (vectorForEnd != null) {
reverseLayout = vectorForEnd.x < 0 || vectorForEnd.y < 0;
return reverseLayout
(forwardDirection ?
centerPosition - mSpanCount :
centerPosition)
(forwardDirection ?
centerPosition + mSpanCount :
centerPosition);
@NonNull
private OrientationHelper getVerticalHelper(@NonNull RecyclerView.LayoutManager layoutManager) {
if (mVerticalHelper == null) {
mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager);
return mVerticalHelper;
* distance to start.
private int distanceToStart(View targetView,
OrientationHelper helper) {
return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding();
* distance to center.
private int distanceToCenter(@NonNull RecyclerView.LayoutManager layoutManager,
@NonNull View targetView,
OrientationHelper helper) {
final int childCenter = helper.getDecoratedStart(targetView)
+ (helper.getDecoratedMeasurement(targetView) / 2);
final int containerCenter;
if (layoutManager.getClipToPadding()) {
containerCenter = helper.getStartAfterPadding() + helper.getTotalSpace() / 2;
} else {
containerCenter = helper.getEnd() / 2;
return childCenter - containerCenter;
@NonNull
private OrientationHelper getHorizontalHelper(
@NonNull RecyclerView.LayoutManager layoutManager) {
if (mHorizontalHelper == null) {
mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
return mHorizontalHelper;
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.