Automatically scroll to bottom of RecyclerView

Viewed 31719

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!

7 Answers

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.

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.

  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);
    }
}

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)
Related