RecyclerView scroll to position when a new item is added

风格不统一 提交于 2020-01-13 07:51:11

问题


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>

回答1:


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.




回答2:


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



回答3:


ישו אוהב אותך's solution worked on other projects. But setting recyclerView.scrollToPosition() didn't work for me. This is what finally did the job:

public void addNewCard() {
    data.add("New");
    adapter.notifyItemInserted(data.size());

    scrollView.post(new Runnable() {
        @Override
        public void run() {
            scrollView.scrollTo(0,buttonAddNewItem.getTop());
        }
    });
}



回答4:


Maybe this will help someone

@Override
public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
    if (pingAdapter != null) {

        Ping ping = dataSnapshot.getValue(Ping.class);
        pingAdapter.pings.add(ping);
        recyclerView.smoothScrollToPosition(pingAdapter.getItemCount());

        pingAdapter.notifyDataSetChanged();
    }
}
recyclerView.smoothScrollToPosition(pingAdapter.pings.size());

is even faster




回答5:


This is happening because your

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

is getting called first and then the list is being initialized. You need to add this line after your recycler View view is initialized. You can add this line in a handler.



来源:https://stackoverflow.com/questions/47250907/recyclerview-scroll-to-position-when-a-new-item-is-added

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!