RecyclerView 滚动到添加新项目时的位置
RecyclerView scroll to position when a new item is added
我希望我的 RecyclerView 在列表中添加新项目时滚动到底部。下面是我的代码:
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
adapter = new RecyclerViewAdapter(data, recyclerView);
recyclerView.setAdapter(adapter);
当我点击 RecyclerView
下面的按钮时,数据被添加到列表中:
public void addNewCard() {
data.add("New");
adapter.notifyItemInserted(data.size() - 1);
recyclerView.scrollToPosition(data.size() - 1);
}
每当我添加一个项目时,它总是会向上滚动到最顶部的位置。我尝试使用 smoothScrollToPosition()
并尝试在 LinearLayoutManager
上使用 scrollToPosition()
。我什至尝试使用 ViewTreeObserver
。也尝试更改依赖项中 RecyclerView
的版本。我在 Stack Overflow 上进行了彻底搜索,none 的解决方案对我有用。
对可能出现的问题有什么想法吗?我在片段中使用 RecyclerView
。这可能是问题的原因吗?
我的 .xml 文件 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>
如果要将数据添加到列表底部,您需要在 RecyclerView 布局管理器中使用 setStackFromEnd()
。
但首先,您需要修复适配器。你不能将你的 RecylerView 传递给你的适配器。所以下面的代码是错误的:
...
// This is wrong!!
adapter = new RecyclerViewAdapter(data, recyclerView);
recyclerView.setAdapter(adapter);
您需要将 Adapter 构造函数更改为仅接收数据作为其参数。像这样:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private List<Data> mData;
public RecyclerViewAdapter(List<Data> data) {
this.mData = data;
}
...
}
然后可以通过以下代码设置数据始终添加在最后底部:
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(linearLayoutManager);
adapter = new RecyclerViewAdapter(data);
recyclerView.setAdapter(adapter);
要添加新数据,最好在适配器中创建一个新方法。像这样:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private List<Data> mData;
...
public void addItem(Data datum) {
mData.add(datum);
notifyItemInserted(mData.size());
}
}
每当您添加新数据时,您需要使用scrollToPosition
方法滚动到底部。像这样:
adapter.addItem(newData);
recyclerView.scrollToPosition(adapter.getItemCount() - 1);
请记住,您需要在适配器中覆盖 getItemCount()
。它应该是这样的:
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();
}
...
}
请注意,我在这里使用数据 pojo 作为示例。您需要根据您的数据类型进行更改。
♬但是设置 recyclerView.scrollToPosition()
对我不起作用。这就是最终完成的工作:
public void addNewCard() {
data.add("New");
adapter.notifyItemInserted(data.size());
scrollView.post(new Runnable() {
@Override
public void run() {
scrollView.scrollTo(0,buttonAddNewItem.getTop());
}
});
}
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);
}
}
})
也许这会对某人有所帮助
@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());
更快
发生这种情况是因为您的
recyclerView.scrollToPosition(data.size() - 1);
首先被调用,然后列表被初始化。你需要在你的 recycler View 视图初始化后添加这一行。您可以在处理程序中添加此行。
这是我提出的解决方案,对于基础知识来说已经足够好了,并且不需要任何自定义适配器。
myAdapter.registerAdapterDataObserver(object :
RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
myRecyclerView.scrollToPosition(positionStart)
}
})
这对我有用。
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
super.onChanged()
if (canShowLive()) wvl_log_rv.scrollToPosition(adapter.itemCount - 1)
}
})
Tested & Verified
或者,如果您将 ListAdapter 与 DiffUtill 一起使用并通过 submitList()
提交新列表,则可以使用 ListAdapter 的 onCurrentListChanged
。例如:
override fun onCurrentListChanged(previousList: MutableList<Item>, currentList: MutableList<Item>) {
super.onCurrentListChanged(previousList, currentList)
//E.g. check if new item has been added
if (currentList.size == previousList.size + 1) {
recyclerView.scrollToPosition(currentList.size - 1)
}
}
我希望我的 RecyclerView 在列表中添加新项目时滚动到底部。下面是我的代码:
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
adapter = new RecyclerViewAdapter(data, recyclerView);
recyclerView.setAdapter(adapter);
当我点击 RecyclerView
下面的按钮时,数据被添加到列表中:
public void addNewCard() {
data.add("New");
adapter.notifyItemInserted(data.size() - 1);
recyclerView.scrollToPosition(data.size() - 1);
}
每当我添加一个项目时,它总是会向上滚动到最顶部的位置。我尝试使用 smoothScrollToPosition()
并尝试在 LinearLayoutManager
上使用 scrollToPosition()
。我什至尝试使用 ViewTreeObserver
。也尝试更改依赖项中 RecyclerView
的版本。我在 Stack Overflow 上进行了彻底搜索,none 的解决方案对我有用。
对可能出现的问题有什么想法吗?我在片段中使用 RecyclerView
。这可能是问题的原因吗?
我的 .xml 文件 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>
如果要将数据添加到列表底部,您需要在 RecyclerView 布局管理器中使用 setStackFromEnd()
。
但首先,您需要修复适配器。你不能将你的 RecylerView 传递给你的适配器。所以下面的代码是错误的:
...
// This is wrong!!
adapter = new RecyclerViewAdapter(data, recyclerView);
recyclerView.setAdapter(adapter);
您需要将 Adapter 构造函数更改为仅接收数据作为其参数。像这样:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private List<Data> mData;
public RecyclerViewAdapter(List<Data> data) {
this.mData = data;
}
...
}
然后可以通过以下代码设置数据始终添加在最后底部:
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(linearLayoutManager);
adapter = new RecyclerViewAdapter(data);
recyclerView.setAdapter(adapter);
要添加新数据,最好在适配器中创建一个新方法。像这样:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private List<Data> mData;
...
public void addItem(Data datum) {
mData.add(datum);
notifyItemInserted(mData.size());
}
}
每当您添加新数据时,您需要使用scrollToPosition
方法滚动到底部。像这样:
adapter.addItem(newData);
recyclerView.scrollToPosition(adapter.getItemCount() - 1);
请记住,您需要在适配器中覆盖 getItemCount()
。它应该是这样的:
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();
}
...
}
请注意,我在这里使用数据 pojo 作为示例。您需要根据您的数据类型进行更改。
♬但是设置 recyclerView.scrollToPosition()
对我不起作用。这就是最终完成的工作:
public void addNewCard() {
data.add("New");
adapter.notifyItemInserted(data.size());
scrollView.post(new Runnable() {
@Override
public void run() {
scrollView.scrollTo(0,buttonAddNewItem.getTop());
}
});
}
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);
}
}
})
也许这会对某人有所帮助
@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());
更快
发生这种情况是因为您的
recyclerView.scrollToPosition(data.size() - 1);
首先被调用,然后列表被初始化。你需要在你的 recycler View 视图初始化后添加这一行。您可以在处理程序中添加此行。
这是我提出的解决方案,对于基础知识来说已经足够好了,并且不需要任何自定义适配器。
myAdapter.registerAdapterDataObserver(object :
RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
myRecyclerView.scrollToPosition(positionStart)
}
})
这对我有用。
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
super.onChanged()
if (canShowLive()) wvl_log_rv.scrollToPosition(adapter.itemCount - 1)
}
})
Tested & Verified
或者,如果您将 ListAdapter 与 DiffUtill 一起使用并通过 submitList()
提交新列表,则可以使用 ListAdapter 的 onCurrentListChanged
。例如:
override fun onCurrentListChanged(previousList: MutableList<Item>, currentList: MutableList<Item>) {
super.onCurrentListChanged(previousList, currentList)
//E.g. check if new item has been added
if (currentList.size == previousList.size + 1) {
recyclerView.scrollToPosition(currentList.size - 1)
}
}