[java] How to scroll to the bottom of a RecyclerView? scrollToPosition doesn't work

I'd like to scroll to the bottom of the RecyclerView list after loading the activity.

GENERIC_MESSAGE_LIST = (ArrayList) intent.getExtras().getParcelableArrayList(ConversationsAdapter.EXTRA_MESSAGE);
conversationView = (RecyclerView) findViewById(R.id.list_messages);
conversationView.setHasFixedSize(true);
conversationViewLayoutManager = new LinearLayoutManager(this);
conversationView.setLayoutManager(conversationViewLayoutManager);
conversationViewAdapter = new ConversationAdapter(GENERIC_MESSAGE_LIST, this);
conversationView.setAdapter(conversationViewAdapter);

conversationView.scrollTo(...) throws an exception about being not supported in RecyclerView, and conversationView.scrollToPosition(...) doesn't seem to do anything.

After the above block of code, I added

conversationView.scrollToPosition(GENERIC_MESSAGE_LIST.size() + 1)

which doesn't work. There are 30 elements in GENERIC_MESSAGE_LIST.

This question is related to java android scroll android-recyclerview

The answer is


In Kotlin:

recyclerView.viewTreeObserver.addOnGlobalLayoutListener { scrollToEnd() }

private fun scrollToEnd() =
        (adapter.itemCount - 1).takeIf { it > 0 }?.let(recyclerView::smoothScrollToPosition)

this code will give you latest post first, i think this answer is helpful.

    mInstaList=(RecyclerView)findViewById(R.id.insta_list);
    mInstaList.setHasFixedSize(true);

    LinearLayoutManager layoutManager = new LinearLayoutManager(this);
    layoutManager.setOrientation(LinearLayoutManager.VERTICAL);

    mInstaList.setLayoutManager(layoutManager);
    layoutManager.setStackFromEnd(true);
    layoutManager.setReverseLayout(true);

If none of these worked,

you should try to use :

ConstraintLayout targetView = (ConstraintLayout) recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount()-1).itemView;
targetView.getParent().requestChildFocus(targetView, targetView);

By doing this, you are requesting a certain ConstraintLayout (Or whatever you have) to be displayed. The scroll is instant.

I works even with keyboard shown.


Solution for Kotlin:

apply below code after setting "recyclerView.adapter" or after "recyclerView.adapter.notifyDataSetChanged()"

recyclerView.scrollToPosition(recyclerView.adapter.itemCount - 1)

I was looking at this post to find the answer but... I think everyone on this post was facing the same scenario as me: scrollToPosition() was fully ignored, for an evident reason.

What I was using?

recyclerView.scrollToPosition(items.size());

... what WORKED?

recyclerView.scrollToPosition(items.size() - 1);

The answer is

recyclerView.scrollToPosition(arrayList.size() - 1);

Everyone has mentioned it.

But the problem I was facing was that it was not placed correctly.

I tried and placed just after the adapter.notifyDataSetChanged(); and it worked. Whenever, data in your recycler view changes, it automatically scrolls to the bottom like after sending messages or you open the chat list for the first time.

Note : This code was tasted in Java.

actual code for me was :

//scroll to bottom after sending message.
binding.chatRecyclerView.scrollToPosition(messageArrayList.size() - 1);

Add this code after sending message and before getting message from server

recyclerView.scrollToPosition(mChatList.size() - 1);

First time scroll when entering in recycler view first time then use

linearLayoutManager.scrollToPositionWithOffset(messageHashMap.size()-1

put in minus for scroll down for scroll up put in positive value);

if the view is very big in height then scrolltoposition particular offset is used for the top of view then you use

int overallXScroldl =chatMessageBinding.rvChat.computeVerticalScrollOffset();
chatMessageBinding.rvChat.smoothScrollBy(0, Math.abs(overallXScroldl));

Only Ian's answer was able to make my RecyclerView scroll to a specified position. However, The RecyclerView was not able to scroll afterwards when I used scrollToPosition(). smoothScrollToPosition() worked but the initial animation made it too slow when the list was long. The reason was the listener was not removed. I used the code below to remove the current ViewTreeObserver and it worked as a charm.

    mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mRecyclerView.scrollToPosition(mPosition);
            mRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    });

I know its late to answer here, still if anybody want to know solution is below

conversationView.smoothScrollToPosition(conversationView.getAdapter().getItemCount() - 1);

Roc answer is a great help. I would like to add a small block to it:

mRecyclerView.scrollToPosition(mAdapter.getItemCount() - 1);

In my case where views do not have the same height, calling scrollToPosition on the LayoutManager worked to really scroll to the bottom and see fully the last item:

recycler.getLayoutManager().scrollToPosition(adapter.getItemCount() - 1);

To scrolldown from any position in the recyclerview to bottom

edittext.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                rv.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                      rv.scrollToPosition(rv.getAdapter().getItemCount() - 1);
                    }
                }, 1000);
            }
        });

If you want just starting from the end use:

layoutManager.stackFromEnd = true

(Kotlin solution)


This works perfectly fine for me:

AdapterChart adapterChart = new AdapterChart(getContext(),messageList);
recyclerView.setAdapter(adapterChart);
recyclerView.scrollToPosition(recyclerView.getAdapter().getItemCount()-1);

When you call setAdapter, that does not immediately lay out and position items on the screen (that takes a single layout pass) hence your scrollToPosition() call has no actual elements to scroll to when you call it.

Instead, you should register a ViewTreeObserver.OnGlobalLayoutListener (via addOnGlobalLayoutListner() from a ViewTreeObserver created by conversationView.getViewTreeObserver()) which delays your scrollToPosition() until after the first layout pass:

conversationView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
  public void onGlobalLayout() {
    conversationView.scrollToPosition(GENERIC_MESSAGE_LIST.size();
    // Unregister the listener to only call scrollToPosition once
    conversationView.getViewTreeObserver().removeGlobalOnLayoutListener(this);

    // Use vto.removeOnGlobalLayoutListener(this) on API16+ devices as 
    // removeGlobalOnLayoutListener is deprecated.
    // They do the same thing, just a rename so your choice.
  }
});

IF you have adapter attached with recyclerView then just do this.

mRecyclerView.smoothScrollToPosition(mRecyclerView.getAdapter().getItemCount());


Tried a method of @galex, it worked until refactoring. So I used an answer of @yanchenko and changed a bit. Probably this is because I called scrolling from onCreateView(), where a fragment view was built (and probably didn't have right size).

private fun scrollPhotosToEnd(view: View) {
    view.recycler_view.viewTreeObserver.addOnGlobalLayoutListener(object :
        ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                view.recycler_view.viewTreeObserver.removeOnGlobalLayoutListener(this)
            } else {
                @Suppress("DEPRECATION")
                view.recycler_view.viewTreeObserver.removeGlobalOnLayoutListener(this)
            }
            adapter?.itemCount?.takeIf { it > 0 }?.let {
                view.recycler_view.scrollToPosition(it - 1)
            }
        }
    })
}

You can also add a check of viewTreeObserver.isAlive like in https://stackoverflow.com/a/39001731/2914140.


class MyLayoutManager extends LinearLayoutManager {

  public MyLayoutManager(Context context) {
    super(context, LinearLayoutManager.VERTICAL, false);
  }

  @Override public void smoothScrollToPosition(RecyclerView recyclerView,
      final RecyclerView.State state, final int position) {

    int fcvip = findFirstCompletelyVisibleItemPosition();
    int lcvip = findLastCompletelyVisibleItemPosition();

    if (position < fcvip || lcvip < position) {
      // scrolling to invisible position

      float fcviY = findViewByPosition(fcvip).getY();
      float lcviY = findViewByPosition(lcvip).getY();

      recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {

        int currentState = RecyclerView.SCROLL_STATE_IDLE;

        @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

          if (currentState == RecyclerView.SCROLL_STATE_SETTLING
              && newState == RecyclerView.SCROLL_STATE_IDLE) {

            // recursive scrolling
            smoothScrollToPosition(recyclerView, state, position);
          }

          currentState = newState;
        }

        @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

          int fcvip = findFirstCompletelyVisibleItemPosition();
          int lcvip = findLastCompletelyVisibleItemPosition();

          if ((dy < 0 && fcvip == position) || (dy > 0 && lcvip == position)) {
            // stop scrolling
            recyclerView.setOnScrollListener(null);
          }
        }
      });

      if (position < fcvip) {
        // scroll up

        recyclerView.smoothScrollBy(0, (int) (fcviY - lcviY));
      } else {
        // scroll down

        recyclerView.smoothScrollBy(0, (int) (lcviY - fcviY));
      }
    } else {
      // scrolling to visible position

      float fromY = findViewByPosition(fcvip).getY();
      float targetY = findViewByPosition(position).getY();

      recyclerView.smoothScrollBy(0, (int) (targetY - fromY));
    }
  }
}

and

MyLayoutManager layoutManager = new MyLayoutManager(context);
recyclerView.setLayoutManager(layoutManager);

RecyclerView.Adapter adapter = new YourAdapter();
recyclerView.setAdapter(adapter);

recyclerView.smoothScrollToPosition(adapter.getItemCount() - 1);

above code works, but it's not smooth and not cool.


You must hide AppBarLayout before scrollToPosition if you are using him


You can scroll to the bottom of the last item, if the height of the last item is too large, you need to offset

 private void scrollToBottom(final RecyclerView recyclerView) {
        // scroll to last item to get the view of last item
        final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
        final RecyclerView.Adapter adapter = recyclerView.getAdapter();
        final int lastItemPosition = adapter.getItemCount() - 1;
    
        layoutManager.scrollToPositionWithOffset(lastItemPosition, 0);
        recyclerView.post(new Runnable() {
            @Override
            public void run() {
                // then scroll to specific offset
                View target = layoutManager.findViewByPosition(lastItemPosition);
                if (target != null) {
                    int offset = recyclerView.getMeasuredHeight() - target.getMeasuredHeight();
                    layoutManager.scrollToPositionWithOffset(lastItemPosition, offset);
                }
            }
        });



    }

Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to android

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How to implement a simple scenario the OO way My eclipse won't open, i download the bundle pack it keeps saying error log getting " (1) no such column: _id10 " error java doesn't run if structure inside of onclick listener Cannot retrieve string(s) from preferences (settings) strange error in my Animation Drawable how to put image in a bundle and pass it to another activity FragmentActivity to Fragment A failure occurred while executing com.android.build.gradle.internal.tasks

Examples related to scroll

How to window.scrollTo() with a smooth effect Angular 2 Scroll to bottom (Chat style) Scroll to the top of the page after render in react.js Get div's offsetTop positions in React RecyclerView - How to smooth scroll to top of item on a certain position? Detecting scroll direction How to disable RecyclerView scrolling? How can I scroll a div to be visible in ReactJS? Make a nav bar stick Disable Scrolling on Body

Examples related to android-recyclerview

Failed to resolve: com.android.support:cardview-v7:26.0.0 android CardView background color always white Changing background color of selected item in recyclerview Simple Android grid example using RecyclerView with GridLayoutManager (like the old GridView) Simple Android RecyclerView example Android Horizontal RecyclerView scroll Direction Margin between items in recycler view Android How to add a recyclerView inside another recyclerView RecyclerView - Get view at particular position Recyclerview inside ScrollView not scrolling smoothly