Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RecyclerView scroll to position when a new item is added

I want my RecyclerView to scroll to the bottom when a new item is added to the list. Below is my code:

RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity()); recyclerView.setLayoutManager(layoutManager);  adapter = new RecyclerViewAdapter(data, recyclerView); recyclerView.setAdapter(adapter); 

And when I click a button which is below the RecyclerView, data is added to the list:

public void addNewCard() {     data.add("New");     adapter.notifyItemInserted(data.size() - 1);     recyclerView.scrollToPosition(data.size() - 1); } 

Whenever I add an item, it always gets scrolled up to the topmost position. I tried using smoothScrollToPosition() and tried using scrollToPosition() on LinearLayoutManager too. I even tried using ViewTreeObserver. Tried changing the version of RecyclerView in dependencies too. I searched thoroughly on Stack Overflow and none of the solutions work for me.

Any ideas on what could be the problem? I'm using RecyclerView inside a fragment. Could that be a cause of the problem?

My .xml file for the RecyclerView

<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.NestedScrollView  xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/scroll_view_recycler" android:layout_width="match_parent" android:layout_height="match_parent">  <RelativeLayout     android:id="@+id/rel_layout"     android:layout_width="match_parent"     android:layout_height="wrap_content">      <android.support.v7.widget.RecyclerView         android:id="@+id/listView"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:layout_marginTop="6dp" />      <Button         android:id="@+id/button_add_new_card"         style="@style/Widget.AppCompat.Button.Borderless"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:layout_below="@id/listView"         android:layout_marginBottom="16dp"         android:layout_marginTop="8dp"         android:padding="20dp"         android:text="+ Add new Item" /> </RelativeLayout> </android.support.v4.widget.NestedScrollView> 
like image 906
Arshad Yusuf Avatar asked Nov 12 '17 16:11

Arshad Yusuf


People also ask

How do you tell the RecyclerView to start at a specific item position?

If onLayoutChildren is called by RecyclerView, it checks if adapters itemCount is already > 0. If true, it calls scrollToPositionWithOffset() . So I can tell immediately what position should be visible, but it will not be told to LayoutManager before position exists in Adapter. Show activity on this post.

How scroll RecyclerView to bottom in android programmatically?

mLinearLayoutManager = new LinearLayoutManager(this); recyclerView. setLayoutManager(mLinearLayoutManager); 3). On your Button onClick , do this to scroll to the bottom of your RecyclerView .

Does RecyclerView scroll?

To help you build apps with lists, Android provides the RecyclerView . RecyclerView is designed to be very efficient, even with large lists, by reusing, or recycling, the views that have scrolled off the screen.


2 Answers

If want to add the data to the bottom of the list you need to use setStackFromEnd() in RecyclerView Layout Manager.

But first, you need to fix your Adapter. You must not pass your RecylerView to your Adapter. So the following code is wrong:

... // This is wrong!! adapter = new RecyclerViewAdapter(data, recyclerView);  recyclerView.setAdapter(adapter); 

You need to change your Adapter constructor to only receive the data as its parameter. Something like this:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {    private List<Data> mData;    public RecyclerViewAdapter(List<Data> data) {     this.mData = data;   }    ... } 

Then you can set the data to always added at the last bottom with the following code:

LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); linearLayoutManager.setStackFromEnd(true); recyclerView.setLayoutManager(linearLayoutManager);  adapter = new RecyclerViewAdapter(data); recyclerView.setAdapter(adapter); 

To add the new data, you better to make a new method in the adapter. Something like this:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {    private List<Data> mData;   ...    public void addItem(Data datum) {     mData.add(datum);     notifyItemInserted(mData.size());   } } 

Whenever you have adding a new data, you need to scroll to the bottom with scrollToPosition method. Something like this:

adapter.addItem(newData); recyclerView.scrollToPosition(adapter.getItemCount() - 1); 

Remember that you need to override getItemCount() in your Adapter. It should be something like this:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {    private List<Data> mData;   public RecyclerViewAdapter(List<Data> data) {     this.mData = data;   }    // Return the total count of items   @Override   public int getItemCount() {     return mData.size();   }    ... } 

Please be aware that I'm using a Data pojo as a sample here. You need to change it according to your data type.

like image 187
ישו אוהב אותך Avatar answered Oct 05 '22 11:10

ישו אוהב אותך


adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {     override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {         super.onItemRangeInserted(positionStart, itemCount)          val msgCount = adapter.getItemCount()         val lastVisiblePosition =              linearLayoutManager.findLastCompletelyVisibleItemPosition()          if (lastVisiblePosition == -1 || positionStart >= msgCount - 1 &&              lastVisiblePosition == positionStart - 1) {             recyclerView.scrollToPosition(positionStart)         } else {             recyclerView.scrollToPosition(adapter.getItemCount() - 1);         }     } }) 
like image 40
Mahesh Chakkarwar Avatar answered Oct 05 '22 11:10

Mahesh Chakkarwar