我想把ListView改为RecyclerView。我想在RecyclerView中使用OnScrollListener的onScroll来确定用户是否滚动到列表的末尾。
我如何知道用户是否滚动到列表的末尾以便我可以从REST服务获取新数据?
我想把ListView改为RecyclerView。我想在RecyclerView中使用OnScrollListener的onScroll来确定用户是否滚动到列表的末尾。
我如何知道用户是否滚动到列表的末尾以便我可以从REST服务获取新数据?
当前回答
if (layoutManager.findLastCompletelyVisibleItemPosition() ==
recyclerAdapter.getItemCount() - 1) {
//load more items.
}
公平而简单。 这是可行的。
其他回答
if (layoutManager.findLastCompletelyVisibleItemPosition() ==
recyclerAdapter.getItemCount() - 1) {
//load more items.
}
公平而简单。 这是可行的。
虽然接受的答案工作得很好,但下面的解决方案使用addOnScrollListener,因为setOnScrollListener已弃用,并减少了变量的数量,以及if条件。
final LinearLayoutManager layoutManager = new LinearLayoutManager(context);
feedsRecyclerView.setLayoutManager(layoutManager);
feedsRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy > 0) {
if ((layoutManager.getChildCount() + layoutManager.findFirstVisibleItemPosition()) >= layoutManager.getItemCount()) {
Log.d("TAG", "End of list");
//loadMore();
}
}
}
});
我的答案是一个改良版的努尔。我从一个ListView,在那里我有EndlessScrollListener(你可以很容易地在SO上找到许多答案)到一个RecyclerView,所以我想要一个endlessrecyscrolllistener轻松地更新我过去的监听器。
下面是代码,希望能有所帮助:
public abstract class EndlessScrollRecyclListener extends RecyclerView.OnScrollListener
{
// The total number of items in the dataset after the last load
private int previousTotalItemCount = 0;
private boolean loading = true;
private int visibleThreshold = 5;
int firstVisibleItem, visibleItemCount, totalItemCount;
private int startingPageIndex = 0;
private int currentPage = 0;
@Override
public void onScrolled(RecyclerView mRecyclerView, int dx, int dy)
{
super.onScrolled(mRecyclerView, dx, dy);
LinearLayoutManager mLayoutManager = (LinearLayoutManager) mRecyclerView
.getLayoutManager();
visibleItemCount = mRecyclerView.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
onScroll(firstVisibleItem, visibleItemCount, totalItemCount);
}
public void onScroll(int firstVisibleItem, int visibleItemCount, int totalItemCount)
{
// If the total item count is zero and the previous isn't, assume the
// list is invalidated and should be reset back to initial state
if (totalItemCount < previousTotalItemCount)
{
this.currentPage = this.startingPageIndex;
this.previousTotalItemCount = totalItemCount;
if (totalItemCount == 0)
{
this.loading = true;
}
}
// If it’s still loading, we check to see if the dataset count has
// changed, if so we conclude it has finished loading and update the current page
// number and total item count.
if (loading && (totalItemCount > previousTotalItemCount))
{
loading = false;
previousTotalItemCount = totalItemCount;
currentPage++;
}
// If it isn’t currently loading, we check to see if we have breached
// the visibleThreshold and need to reload more data.
// If we do need to reload some more data, we execute onLoadMore to fetch the data.
if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem +
visibleThreshold))
{
onLoadMore(currentPage + 1, totalItemCount);
loading = true;
}
}
// Defines the process for actually loading more data based on page
public abstract void onLoadMore(int page, int totalItemsCount);
}
感谢@Kushal,这是我实现它的方式
private boolean loading = true;
int pastVisiblesItems, visibleItemCount, totalItemCount;
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) { //check for scroll down
visibleItemCount = mLayoutManager.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
loading = false;
Log.v("...", "Last Item Wow !");
// Do pagination.. i.e. fetch new data
loading = true;
}
}
}
}
});
别忘了加上
LinearLayoutManager mLayoutManager;
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
这里我的解决方案使用AsyncListUtil,在网络上说: 注意,这个类使用一个线程来加载数据,所以它适合从二级存储(如磁盘)加载数据,但不适合从网络加载数据。 但是我使用odata来读取数据并工作良好。 我在示例中遗漏了数据实体和网络方法。 我只包括示例适配器。
public class AsyncPlatoAdapter extends RecyclerView.Adapter {
private final AsyncPlatoListUtil mAsyncListUtil;
private final MainActivity mActivity;
private final RecyclerView mRecyclerView;
private final String mFilter;
private final String mOrderby;
private final String mExpand;
public AsyncPlatoAdapter(String filter, String orderby, String expand, RecyclerView recyclerView, MainActivity activity) {
mFilter = filter;
mOrderby = orderby;
mExpand = expand;
mRecyclerView = recyclerView;
mActivity = activity;
mAsyncListUtil = new AsyncPlatoListUtil();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).
inflate(R.layout.plato_cardview, parent, false);
// Create a ViewHolder to find and hold these view references, and
// register OnClick with the view holder:
return new PlatoViewHolderAsync(itemView, this);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final Plato item = mAsyncListUtil.getItem(position);
PlatoViewHolderAsync vh = (PlatoViewHolderAsync) holder;
if (item != null) {
Integer imagen_id = item.Imagen_Id.get();
vh.getBinding().setVariable(BR.plato, item);
vh.getBinding().executePendingBindings();
vh.getImage().setVisibility(View.VISIBLE);
vh.getProgress().setVisibility(View.GONE);
String cacheName = null;
String urlString = null;
if (imagen_id != null) {
cacheName = String.format("imagenes/imagen/%d", imagen_id);
urlString = String.format("%s/menusapi/%s", MainActivity.ROOTPATH, cacheName);
}
ImageHelper.downloadBitmap(mActivity, vh.getImage(), vh.getProgress(), urlString, cacheName, position);
} else {
vh.getBinding().setVariable(BR.plato, item);
vh.getBinding().executePendingBindings();
//show progress while loading.
vh.getImage().setVisibility(View.GONE);
vh.getProgress().setVisibility(View.VISIBLE);
}
}
@Override
public int getItemCount() {
return mAsyncListUtil.getItemCount();
}
public class AsyncPlatoListUtil extends AsyncListUtil<Plato> {
/**
* Creates an AsyncListUtil.
*/
public AsyncPlatoListUtil() {
super(Plato.class, //my data class
10, //page size
new DataCallback<Plato>() {
@Override
public int refreshData() {
//get count calling ../$count ... odata endpoint
return countPlatos(mFilter, mOrderby, mExpand, mActivity);
}
@Override
public void fillData(Plato[] data, int startPosition, int itemCount) {
//get items from odata endpoint using $skip and $top
Platos p = loadPlatos(mFilter, mOrderby, mExpand, startPosition, itemCount, mActivity);
for (int i = 0; i < Math.min(itemCount, p.value.size()); i++) {
data[i] = p.value.get(i);
}
}
}, new ViewCallback() {
@Override
public void getItemRangeInto(int[] outRange) {
//i use LinearLayoutManager in the RecyclerView
LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
outRange[0] = layoutManager.findFirstVisibleItemPosition();
outRange[1] = layoutManager.findLastVisibleItemPosition();
}
@Override
public void onDataRefresh() {
mRecyclerView.getAdapter().notifyDataSetChanged();
}
@Override
public void onItemLoaded(int position) {
mRecyclerView.getAdapter().notifyItemChanged(position);
}
});
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
onRangeChanged();
}
});
}
}
}