'Automatically scroll to bottom of RecyclerView

I have a fragment that has a RecyclerView inside its layout file. The RecyclerView holds messages in a chat. So naturally, I need the RecyclerView to scroll to the bottom when the chat fragment gets opened.

I tried scrolling directly on the RecyclerView:

var mRecyclerView = view.FindViewById<RecyclerView>
mRecyclerView.ScrollToPosition(mMessages.Count-1);

Second method:

LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(Application.Context);
mRecyclerView.SetLayoutManager(mLinearLayoutManager);
mLinearLayoutManager.ScrollToPosition(mMessages.Count - 1);      

Third method:

LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(Application.Context);
mRecyclerView.SetLayoutManager(mLinearLayoutManager);
mLinearLayoutManager.ScrollToPositionWithOffset(mMessages.Count - 1, 0);

Unfortunately, nothing happens in either case. Any suggestions would be greatly appreciated!



Solution 1:[1]

Please use smoothScrollToPosition to fix your issue. I always use smoothScrollToPosition for redirecting to any position.

Make sure, mMessages size is good as you thinking.

Example,

RecyclerView rv = (RecyclerView)findViewById(R.id.recyclerView);
rv.smoothScrollToPosition(mMessages.count-1);

Solution 2:[2]

It's Simple change your code with

    RecyclerView recyclerView = findViewById(R.id.recyclerView);
    LinearLayoutManager layoutManager = new LinearLayoutManager(this);
    layoutManager.setStackFromEnd(true);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(mAdapter);
    recyclerView.smoothScrollToPosition(mAdapter.getItemCount());

If You have given ScrollView or NestedScrollView in the parent of RecyclerView then it will not work. Because it only works when RecyclerView doesn't have any parent layout like ScrollView. hope it will fix your error.

Solution 3:[3]

You can set setStackFromEnd=true that will set the view to show the last element, the layout direction will remain the same.

After edit I have updated: just like this:

   LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(Application.Context);
   mLinearLayoutManager.setStackFromEnd(true); 
   mRecyclerView.SetLayoutManager(mLinearLayoutManager);
   mRecyclerView.scrollToPosition(mMessages.Count-1);

please check the documentation.

Edit: the problem is you are calling scrollToPosition without setting any layout manager to the recyclerview.

Considering to the scrollToPosition function in RecyclerView class, your case makes sense.

/**
     * Convenience method to scroll to a certain position.
     *
     * RecyclerView does not implement scrolling logic, rather forwards the call to
     * {@link android.support.v7.widget.RecyclerView.LayoutManager#scrollToPosition(int)}
     * @param position Scroll to this adapter position
     * @see android.support.v7.widget.RecyclerView.LayoutManager#scrollToPosition(int)
     */
    public void scrollToPosition(int position) {
        if (mLayoutFrozen) {
            return;
        }
        stopScroll();
        if (mLayout == null) {
            Log.e(TAG, "Cannot scroll to position a LayoutManager set. " +
                    "Call setLayoutManager with a non-null argument.");
            return;
        }
        mLayout.scrollToPosition(position);
        awakenScrollBars();
    }

Cannot scroll to position a LayoutManager set. Call setLayoutManager with a non-null argument.

Solution 4:[4]

I believe you are not calling it in right way. You have to pass LinearLayoutManager as well along with recycler view to make it work. Here how I have made it work

mLayoutManager.smoothScrollToPosition(mRecyclerView, null, array.size() - 1);

Solution 5:[5]

I found the issue, set RecyclerView scrollToPosition or smoothScrollToPosition after setting the LayoutManager.

RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.scrollToPosition(mMessages.count - 1);

Hopes it help you.

Solution 6:[6]

  1. If you want to directly scroll in the last item you can just use this code.

binding.recyclerView.smoothScrollToPosition(adapter.itemCount-1)

  1. If you want to add continuous scrolling for the recyclerview, you can use this class.
public class AutoScrollRecyclerView extends RecyclerView {
    private static long delayTime = 45;// How long after the interval to perform scrolling
    AutoPollTask autoPollTask;// Scroll thread
    private boolean running; // Is it rolling?
    private boolean canRun;// Can it be automatically scrolled, depending on whether the data exceeds the screen

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

    public AutoScrollRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        autoPollTask = new AutoPollTask(this);// Instantiate the scroll refresh thread
    }

    static class AutoPollTask implements Runnable {
        private final WeakReference<AutoScrollRecyclerView> mReference;

        // Use weak references to hold external class references to prevent memory leaks
        public AutoPollTask(AutoScrollRecyclerView reference) {
            this.mReference = new WeakReference<>(reference);
        }

        @Override
        public void run() {
            AutoScrollRecyclerView recyclerView = mReference.get();// Get the recyclerview object
            if (recyclerView != null && recyclerView.running && recyclerView.canRun) {
                recyclerView.scrollBy(2, 2);// Note the difference between scrollBy and scrollTo
                //delayed to send
                recyclerView.postDelayed(recyclerView.autoPollTask, delayTime);
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
                /*if (running)
                    stop();*/
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_OUTSIDE:
                /*if (canRun)
                    start();*/
                break;
        }
        return super.onTouchEvent(e);
    }

    //Open: If it is running, stop first -> then open
    public void start() {
        if (running)
            stop();
        canRun = true;
        running = true;
        postDelayed(autoPollTask, delayTime);
    }
    
    public void stop() {
        running = false;
        removeCallbacks(autoPollTask);
    }
}

Solution 7:[7]

If You have given ScrollView or NestedScrollView in the parent of recyclerView then try this:

parentNestedScrollView.smoothScrollTo(0, parentNestedScrollView.bottom)

Sometimes this may not work, as an attempt to update the scroll position will be made before the adapter displays the new item, so we need to use delay:

 popupView.postDelayed({
        parentNestedScrollView.smoothScrollTo(0, parentNestedScrollView.bottom)
 }, 200)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Narendra Sorathiya
Solution 2
Solution 3
Solution 4 Irfan Raza
Solution 5 Shamsul
Solution 6 Md.Tarikul Islam
Solution 7 tasjapr