简体   繁体   中英

How to make auto smooth scroll with offset Recycler View?

There is such issue, I have horizontal RecyclerView where each cell less than width of screen.

So I found a solution here

RecyclerVIew auto scroll to display all the elements as in News Feed etc.,

All work excellent if one cell take whole width of the screen otherwise(if each cell take 95% of screen width) every auto swipe place the cell at the beginner of screen (right side) and it is logical. So at the end of one visible cell it is start of another cell

在此处输入图片说明

it is doesn't looks good. I need this cell to be at the middle of the screen like this.

I need to see previous cell - current - next one

在此处输入图片说明

Now I would like to explain some magic how I make current smooth scroll (as I mentioned at link above)

this method in my CustomLinnearLayoutManager

@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position)
{
    LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext())
    {
        @Override
        public PointF computeScrollVectorForPosition(int targetPosition)
        {
            return SmoothLayoutManager.this.computeScrollVectorForPosition(targetPosition);
        }

        @Override
        protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics)
        {
            return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
        }
    };

    linearSmoothScroller.setTargetPosition(position);
    startSmoothScroll(linearSmoothScroller);
}

But this method works without offset

I found out one more method that can provide desired offset

scrollToPositionWithOffset(final int position, final int offset)

And it is looks like exactly what I need , but this method works without smooth animation.

So, eventually my question is : how to apply animation logic from first method to second (that with offset)

Feel free to ask

To auto snapping and showing one item at center of RecyclerView , simply you need to use LinearSnapHelper like following:

LinearSnapHelper snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);

If you want to scroll to a specific item programmatically, LinearSnapHelper handles snapping functionality too.

SmoothScroller smoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
        @Override
        protected int getVerticalSnapPreference() {
            return LinearSmoothScroller.SNAP_TO_ANY;
        }

        @Override
        protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
            return 120f / displayMetrics.densityDpi;
        }
    };

...

smoothScroller.setTargetPosition(position);
recyclerView.getLayoutManager().startSmoothScroll(smoothScroller);

Here is the visual result:
.

.................. Manually Scrolling ........................... Programmatically Scrolling ..........

例例

Eventually, I found the way thanks a lot to @aminography for his answer and also one more answer help me a lot

https://stackoverflow.com/a/39654328

Actually now I have such implementation

My custom LinnearLayoutManager implementation

public class SmoothLayoutManager extends LinearLayoutManager
{
public static final int X_25 = 25;
public static final int X_200 = 200;
public static final float DEFAULT = X_25;

/**
 * !! IMPORTANT !!
 * If you need to add new value, don't forget add it here also
 */
@Retention(RetentionPolicy.SOURCE)
@IntDef({X_25, X_200})
private @interface Speed
{

}

private static float MILLISECONDS_PER_INCH = DEFAULT;

public SmoothLayoutManager(Context context)
{
    super(context);
}

public SmoothLayoutManager(Context context, int orientation, boolean reverseLayout)
{
    super(context, orientation, reverseLayout);
}

public SmoothLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
{
    super(context, attrs, defStyleAttr, defStyleRes);
}

public SmoothLayoutManager setSpeedOfSmooth(@Speed int iSpeed)
{
    MILLISECONDS_PER_INCH = iSpeed;

    return this;
}

@Override
public void scrollToPositionWithOffset(final int position, final int offset)
{
    super.scrollToPositionWithOffset(position, offset);
}

@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position)
{
    RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(recyclerView.getContext())
    {
        @Override
        public PointF computeScrollVectorForPosition(int targetPosition)
        {
            return SmoothLayoutManager.this.computeScrollVectorForPosition(targetPosition);
        }

        @Override
        protected int getVerticalSnapPreference()
        {
            return LinearSmoothScroller.SNAP_TO_ANY;
        }

        @Override
        protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics)
        {
            return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
        }

        @Override
        public int calculateDtToFit(final int viewStart, final int viewEnd, final int boxStart, final int boxEnd, final int snapPreference)
        {
            return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
        }
    };

    smoothScroller.setTargetPosition(position);
    startSmoothScroll(smoothScroller);
}
}

And this is how I make set

private void setRv(Context iC)
    {
        RecyclerView.Adapter adapter = new UpSaleInnerAdapter(mPicasso, mInflater, iLink -> mListener.onButtonClick(iLink));

        mRv.setLayoutManager(new SmoothLayoutManager(iC, LinearLayoutManager.HORIZONTAL, false).setSpeedOfSmooth(SmoothLayoutManager.X_200));
        mRv.setAdapter(adapter);

        SnapHelper snapHelper = new LinearSnapHelper();
        snapHelper.attachToRecyclerView(mRv);
    }

Note :

I noticed that sometimes if you make fast swipe, so SnapHelper a little bit confused and pass more cells that need... like a turbo mode :)

If someone will find how to fix it, let me know.

Thanks!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM