I have a Fragment with a RecyclerView. It works as a chat.
I request to my backend the last 50 messages and I load them in the recycler view
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(layoutManager);
mAdapter = new ChatMessagesAdapter(recyclerView, messages, getActivity());
recyclerView.setAdapter(mAdapter);
recyclerView.getLayoutManager().scrollToPosition(messages.size()-1);
mAdapter.notifyDataSetChanged();
Then, when I scroll up I request more messages with OnScrollListener and I load them
messages.addAll(0, oldMessages);
mAdapter.notifyDataSetChanged();
mAdapter.setLoaded();
recyclerView.getLayoutManager().scrollToPosition((oldMessages.size()) -1);
But as I set the the recyclerView in the first load with
layoutManager.setStackFromEnd(true);
when I load the old messages the scroll moves first item shown(before the last) to the bottom.
How can I add old messages on top and continue the scrolling like if the items were there from the first load? Without move the focus to the bottom
Use notifyItemRangeInserted instead of notifyDataSetChanged.
Use below code to update your adapter:
public void addList(List<ChatMessage> items) {
chatMessages.addAll(0, items);
notifyItemRangeInserted(0,items.size());
notifyItemChanged(items.size());//Only To update the last top item cause in my case it was the date header so i need to notify it
}
Related
I have 3 buttons and a Recyclerview. On click of each button, I am updating the Recyclerview list. I am using the following way to update the Recyclerview list:
fun updateList(list: List<SortFilterItem>){
itemList.clear()
itemList.addAll(list)
notifyDataSetChanged()
}
The problem is if I scroll the list to a certain position and then click on any of the Button the list is updated but the position is not reset to the start position. How can I reset the position of the Recyclerview when I update the list.
LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
layoutManager.scrollToPositionWithOffset(0, 0); //Way I
layoutManager.smoothScrollToPosition(mRecyclerView, null, 0); //Way II
Try yourLayourManager.scrollToPositionWithOffset(0,0), this will scroll until satisfy the offset.
or recyclerView.smoothScrollToPosition(position)
just add line into your button click when you update your code
recyclerView.scrollToPosition(0);
I've created a custom ItemDecoration for a RecyclerView that is using a GridLayoutManager. The ItemDecoration essentially ensures that equivalent spacing between all of the child views is applied within the RecyclerView:
The ItemDecoration is working exactly as I hoped it would and I think it looks great. However, I noticed that I need to add the ItemDecoration before I set the layout manager for my RecyclerView. My main question is: Why is that?
I'm working with some legacy code that uses a CursorLoader to pull RSS feeds from the web and display them to the end user. For whatever reason, the layout manager is being set in onLoadFinished():
#Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
Adapter adapter = new Adapter(cursor);
adapter.setHasStableIds(true);
mRecyclerView.setAdapter(adapter);
GridLayoutManager gridLayoutManager =
new GridLayoutManager(this, mColumnCount, GridLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(gridLayoutManager);
}
I noticed that if I add my ItemDecoration within onLoadFinished(), the margins between the items looks bigger than it really should:
#Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
Adapter adapter = new Adapter(cursor);
adapter.setHasStableIds(true);
mRecyclerView.setAdapter(adapter);
GridLayoutManager gridLayoutManager =
new GridLayoutManager(this, mColumnCount, GridLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(gridLayoutManager);
// Adding the custom ItemDecoration
EqualOffsetItemDecoration itemDecoration = new EqualOffsetItemDecoration(this, R.dimen.card_view_margin, mColumnCount);
mRecyclerView.addItemDecoration(itemDecoration);
}
The screenshot above shows far more margin than I was expecting since I'm only applying 8dps (the value of card_view_margin). However, if I add the ItemDecoration within onCreate(), then it appears as expected:
#Override
protected void onCreate(Bundle savedInstanceState) {
...
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mColumnCount = getResources().getInteger(R.integer.list_column_count);
/*
In order to have equal spacing along the edges of the screen as well as between the
child views of the RecyclerView, an EqualOffsetItemDecoration is applied to the RecyclerView.
*/
EqualOffsetItemDecoration itemDecoration = new EqualOffsetItemDecoration(this, R.dimen.card_view_margin, mColumnCount);
mRecyclerView.addItemDecoration(itemDecoration);
...
}
...which is the case for the first screenshot. So why does this matter? Why do I need to add the ItemDecoration before applying a layout manager to my RecyclerView? I'm sure that this has something to do with the order in which things are executed under the hood. Any sort of explanation is greatly appreciated :)
FYI, in case anyone is interested in how I created my ItemDecoration, here it is:
https://github.com/mikepalarz/XYZReader/blob/master/app/src/main/java/com/example/xyzreader/ui/EqualOffsetItemDecoration.java
Interesting question, but I don't believe it matters if you set the layout manager before or after the item decoration. Both calls result in a request for layout.
I am going to guess that you are adding the decoration to the RecyclerView more than one time. Since decorations compound, you will see a greater gap with the decoration added two times (or more times) instead of just once.
My recyclerview should open the first item closed. To this end, I wrote these lines.
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
llm.scrollToPosition(1);
paletteRecyclerView.setLayoutManager(llm);
I want to check if it is possible to scroll to position 1 fully. If my recyclerview is small I must open it without closing the first item. How can I check it?
I assume that you want to know if there are items to scroll in RecyclerView. So you can check as below after setting the adapter to the recyclerView.
recyclerView.post(new Runnable() {
#Override
public void run() {
int recyclerViewheight = recyclerView.getHeight();
int totalChildViewsHeight = recyclerView.computeVerticalScrollRange();
if (recyclerViewheight > totalChildViewsHeight) {
//there is no scroll (there are no more items to scroll)
} else {
//there is scroll (there are items to scroll)
}
}
});
Try with below code...
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(llm);
RecyclerView.Adapter adapter = new YourAdapter();
recyclerView.setAdapter(adapter);
recyclerView.scrollToPosition(position);
I'm creating an app with a list of questions in a RecyclerView. In the same parent layout, I have a static TextView above the RecyclerView that displays instruction for a set of questions. What I want is to change the text in the TextView whenever a specific question reaches the top of the RecyclerView when scrolled. How can I accomplish this?
You would need to listen to the scrolling of your RecyclerView and get the first item displayed onto the screen.
Thanksfully, Android let us set a custom ScrollListener to a RecyclerView and with your LayoutManager you are able to know which item is shown first :
// initialize your RecyclerView and your LayoutManager
mLinearLayoutManager = new LinearLayoutManager(getContext());
mRecyclerView.setLayoutManager(mLinearLayoutManager);
// set a custom ScrollListner to your RecyclerView
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
// Get the first visible item
int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
//Now you can use this index to manipulate your TextView
}
});
EDIT : added Mateus Gondim clearance about the LayoutManager
You should override the default Recycler.OnScrollListener.
Have a look at this Code : https://gist.github.com/mipreamble/b6d4b3d65b0b4775a22e
I want the user to be able to navigate to certain positions within a RecyclerView. I can determine the position of the items and when I use recycleView.smoothScrollToPosition() it scrolls to the correct item.
The problem is this item is at the bottom of the screen. How can I scroll so that the item appears at the top (it must be the first visible item).
Here is the code I use to setup the RecyclerView:
recyclerView = (RecyclerView)findViewById(R.id.recyclerview);
recyclerView.setHasFixedSize(false);
recyclerView.setAdapter(actionAdapter);
final LinearLayoutManager layoutManager = new LinearLayoutManager(InteractionTimelineActivity.this, LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setOnScrollListener(new RecyclerScrollListner());
And this is how I scroll:
if (recycleView != null) {
recycleView.smoothScrollToPosition(position + 1);
}
You have to calculate how many items fit on one screen and use that as offset when you scroll! You can use the methods findFirstCompletelyVisibleItemPosition() and findLastCompletelyVisibleItemPosition() of the LayoutManager to calculate the offset like this:
int offset = getLayoutManager()).findLastCompletelyVisibleItemPosition()
- getLayoutManager()).findFirstCompletelyVisibleItemPosition();
And once you have the offset you can scroll like this:
recycleView.smoothScrollToPosition(Math.min(position + offset + 1, adapter.getItemCount()));