Recyclerview Smoothscroll to Position in The Center. Android

RecyclerView smoothScroll to position in the center. android

Yes it's possible.

By implementing RecyclerView.SmoothScroller's method onTargetFound(View, State, Action).

/**
* Called when the target position is laid out. This is the last callback SmoothScroller
* will receive and it should update the provided {@link Action} to define the scroll
* details towards the target view.
* @param targetView The view element which render the target position.
* @param state Transient state of RecyclerView
* @param action Action instance that you should update to define final scroll action
* towards the targetView
*/
abstract protected void onTargetFound(View targetView, State state, Action action);

Specifically in LinearLayoutManager with LinearSmoothScroller:

public class CenterLayoutManager extends LinearLayoutManager {

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

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

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

@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}

private static class CenterSmoothScroller extends LinearSmoothScroller {

CenterSmoothScroller(Context context) {
super(context);
}

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

How to center the Clicked position in the Recyclerview

if you use linearlayoutManager, you can use this code,

linearLayoutManager.scrollToPositionWithOffset(2, 20);

(linearLayoutManager.void scrollToPositionWithOffset (int position,
int offset))

Setting the offset to 0 should align with the top

RecyclerView - How to smooth scroll to top of item on a certain position?

RecyclerView is designed to be extensible, so there is no need to subclass the LayoutManager (as droidev suggested) just to perform the scrolling.

Instead, just create a SmoothScroller with the preference SNAP_TO_START:

RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(context) {
@Override protected int getVerticalSnapPreference() {
return LinearSmoothScroller.SNAP_TO_START;
}
};

Now you set the position where you want to scroll to:

smoothScroller.setTargetPosition(position);

and pass that SmoothScroller to the LayoutManager:

layoutManager.startSmoothScroll(smoothScroller);

Scroll to an item in a RecyclerView, placing it at the center of the screen

I found many answers for achieving this with a smooth scroller, but in case you want to achieve this without smooth scrolling (to immediately jump a large distance for example), you can do it with a normal LinearLayoutManager/GridLayoutManager by calculating the offset yourself.

I subclassed LinearLayoutManager so that I could just use the scrollToPosition function and have it always scroll to that position with the item in the center, but you can just use the scrollToPositionWithOffset function of the LinearLayoutManager with a manual offset each time if you prefer.

class CenterScrollLayoutManager(context: Context, orientation: Int, reverseLayout: Boolean): LinearLayoutManager(context, orientation, reverseLayout) {

override fun scrollToPosition(position: Int) {

//this will place the top of the item at the center of the screen
val height = getApplicationContext().resources.displayMetrics.heightPixels
val offset = height/2

//if you know the item height, you can place the center of the item at the center of the screen
// by subtracting half the height of that item from the offset:
// val height = getApplicationContext().resources.displayMetrics.heightPixels
// //(say item is 40dp tall)
// val itemHeight = 40F * getApplicationContext().resources.displayMetrics.scaledDensity
// val offset = height/2 - itemHeight/2

//depending on if you have a toolbar or other headers above the RecyclerView,
// you may want to subtract their height as well:
// val height = getApplicationContext().resources.displayMetrics.heightPixels
// //(say item is 40dp tall):
// val itemHeight = 40F * getApplicationContext().resources.displayMetrics.scaledDensity
// //(say toolbar is 56dp tall, which is the default action bar height for portrait mode)
// val toolbarHeight = 56F * getApplicationContext().resources.displayMetrics.scaledDensity
// val offset = height/2 - itemHeight/2 - toolbarHeight

//call scrollToPositionWithOffset with the desired offset
super.scrollToPositionWithOffset(position, offset)
}
}

Then, to use it, you need to first set this as the layout manager for your RecyclerView, likely inside OnCreate (if in an activity) or OnViewCreated (if in a fragment):

yourRecyclerView.apply {
adapter = yourRecyclerViewAdapter
layoutManager = CenterScrollLayoutManager(context, LinearLayoutManager.VERTICAL, false)
}

Then, just scroll to a desired position, and the item should be in the center:

yourRecyclerView.scrollToPosition(desiredPosition)

This also works with a GridLayoutManager.

How to make auto smooth scroll with offset Recycler View?

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!

RecyclerView - Scroll To Position Not Working Every Time

I had the same issue some weeks ago, and found only a really bad solution to solve it. Had to use a postDelayed with 200-300ms.

new Handler().postDelayed(new Runnable() {
@Override
public void run() {
yourList.scrollToPosition(position);
}
}, 200);

If you found a better solution, please let me know! Good luck!

Scroll RecyclerView to show selected item on top

If you are using the LinearLayoutManager or Staggered GridLayoutManager, they each have a scrollToPositionWithOffset method that takes both the position and also the offset of the start of the item from the start of the RecyclerView, which seems like it would accomplish what you need (setting the offset to 0 should align with the top).

For instance:

//Scroll item 2 to 20 pixels from the top
linearLayoutManager.scrollToPositionWithOffset(2, 20);


Related Topics



Leave a reply



Submit