The question:
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
.
The Solutions:
Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.
Method 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);
Method 2
Just set setStackFromEnd=true
or setReverseLayout=true
so that LLM will layout items from end.
The difference between these two is that setStackFromEnd
will set the view to show the last element, the layout direction will remain the same. (So, in an left-to-right horizontal Recycler View, the last element will be shown and scrolling to the left will show the earlier elements)
Whereas setReverseLayout
will change the order of the elements added by the Adapter. The layout will start from the last element, which will be the left-most in an LTR Recycler View and then, scrolling to the right will show the earlier elements.
Sample:
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setReverseLayout(true);
_listView.setLayoutManager(linearLayoutManager);
See documentation for details.
Method 3
I know its late to answer here, still if anybody want to know solution is below
conversationView.smoothScrollToPosition(conversationView.getAdapter().getItemCount() - 1);
Method 4
To scrolldown from any position in the recyclerview to bottom
Kotlin
editText.setOnClickListener {
rv.postDelayed({
rv.scrollToPosition(rv.adapter.itemCount - 1)
}, 1000)
}
Java
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);
}
});
Method 5
Add this code after sending message and before getting message from server
recyclerView.scrollToPosition(mChatList.size() - 1);
Method 6
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.
}
});
Method 7
Solution for Kotlin:
apply below code after setting “recyclerView.adapter” or after “recyclerView.adapter.notifyDataSetChanged()”
recyclerView.scrollToPosition(recyclerView.adapter.itemCount - 1)
Method 8
IF you have adapter attached with recyclerView then just do this.
mRecyclerView.smoothScrollToPosition(mRecyclerView.getAdapter().getItemCount());
Method 9
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.
Method 10
In Kotlin:
recyclerView.viewTreeObserver.addOnGlobalLayoutListener { scrollToEnd() }
private fun scrollToEnd() =
(adapter.itemCount - 1).takeIf { it > 0 }?.let(recyclerView::smoothScrollToPosition)
Method 11
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);
Method 12
Roc answer is a great help. I would like to add a small block to it:
mRecyclerView.scrollToPosition(mAdapter.getItemCount() - 1);
Method 13
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);
Method 14
If you are having issues making recyclerview scroll to the latest, check that the recyclerview is not inside a nestedScrollView. That was my issue. I had to remove the nestedScrollview and then the below code worked.
binding.recyclerView.scrollToPosition(adapter.getItemCount() - 1);
Method 15
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));
Method 16
This works perfectly fine for me:
AdapterChart adapterChart = new AdapterChart(getContext(),messageList);
recyclerView.setAdapter(adapterChart);
recyclerView.scrollToPosition(recyclerView.getAdapter().getItemCount()-1);
Method 17
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);
Method 18
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.
Method 19
You must hide AppBarLayout
before scrollToPosition
if you are using him
Method 20
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);
}
}
});
}
Method 21
I know this is too late but this worked for me so that i am answering this question
first,
LinearLayoutManager layoutManager=new LinearLayoutManager(this);
layoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(layoutManager);
after that,
database.addValueEventListener(....){
@override
public void onDataCange(...){
....
....
//put this line here
recyclerView.smoothScrollToPosition(recyclerView.getAdapter().getItemCount()-1);
}
}
Method 22
if you use kotlin, try this
conversationView.post {
scrollToPosition(conversationView?.adapter.itemCount - 1)
}
Method 23
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);
}
});
Method 24
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.
Method 25
If you want just starting from the end use:
layoutManager.stackFromEnd = true
(Kotlin solution)
Method 26
If you working with reversedLayout “chat interface” specially if you have images, you can try the following:
first, register DataObserver with the adapter
chatAdapter.registerAdapterDataObserver(object :
RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int itemCount: Int) {
val messageCount: Int = chatAdapter.itemCount
val lastVisiblePosition: Int =
layoutManager.findLastCompletelyVisibleItemPosition()
if (lastVisiblePosition == -1 || positionStart <= (messageCount - 1)) {
recyclerView.scrollToPosition(positionStart)
}
}
})
this will be called once you set the data for the adapter
second, you have to add a scroll listener to the recyclerView like this:
recyclerView.addOnScrollListener(object
:RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy:
Int) {
super.onScrolled(recyclerView, dx, dy)
val lastVisiblePosition: Int =
layoutManager.findLastCompletelyVisibleItemPosition()
if (lastVisiblePosition != -1 && lastVisiblePosition <
chatAdapter.itemCount - 1) {
recyclerView.smoothScrollToPosition(0)
}
}
})
Method 27
use only gravity for easy solution
android:layout_gravity=”bottom”
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0