如何确定RecyclerView的最后一个项目是否可见在屏幕上?

20

我有一个 RecyclerView,并向其中添加了一组数据。我想在最后一个 RecyclerView 可见项时添加更多数据到列表中。之后,我想进行 Web 服务调用并更新 RecyclerView 的数据。如何实现这个功能?

有任何建议吗?


2
使用 android.support.v7.widget.RecyclerView.OnScrollListener - pskink
我知道滚动监听器,但我的问题是当用户在项目之间删除时,我如何知道我的最后一个列表项已经可见,以便我可以更新列表或进行网络服务调用? - Rajesh Koshti
所以请使用 onBindViewHolder - pskink
1
如果 position == getItemCount() - 1,那就意味着最后一个项目可见。 - pskink
在onBindViewHolder()中,检查位置是否为最后一个位置。如果是,则检查此if (View.getVisibility() == View.VISIBLE)。 - cgr
是的,它对我起作用了。 - Sagar
4个回答

19

一种选择是编辑您的 LayoutManager。这里的想法是找到最后一个可见项的位置。如果该位置等于数据集的最后一项,则应触发重新加载。

    @Override
    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {

        final int result = super.scrollVerticallyBy(dy, recycler, state);

        if (findLastVisibleItemPosition() == mData.length - 1) {
           loadMoreData();
        } 

        return result;

    }

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        super.onLayoutChildren(recycler, state);

        if (findLastVisibleItemPosition() == mData.length - 1) {
           loadMoreData();
        } 
    }

或者,您可以通过适配器的onBindViewHolder方法来实现这一点,尽管这有点像“hack”:

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (position == mData.length - 1) {
            // load more data here.
        }

        /// binding logic
    }

第三个选项是将OnScrollListener添加到RecyclerView中。@velval在此页面上的答案很好地解释了这一点。

无论您选择哪种选项,都应包含代码以防止数据加载逻辑触发过多次(例如,在前一个请求获取更多数据完成并返回新数据之前)。


1
是的,它将在即将变为可见时绑定。因此,最后一个绑定的不一定已经可见。因此,我们仍然需要条件来检查可见性。 他还可以尝试在LinearLayoutManager中使用findLastVisibleItemPosition()。 - cgr
这是一个可以接受的答案,但当我滚动时,它会调用两次WebService(第一次在滚动时,第二次在适配器中的最后一个可见项)。 - Rajesh Koshti
嘿@GilMoshayof,请解释一下我如何使用LinearLayoutManager的第二个选项? - Rajesh Koshti
2
极其不正确的答案。onBindViewHolder()函数不是添加/加载数据的地方。请不要使用这种技术。 - Bugs Happen
1
第一种方法是灾难性的,因为onBindViewHolder不应该寻找更多数据。它只应该将数据绑定到ViewHolder上。第二种方法要好一些,但是为了这么小的任务扩展LayoutManager仍然是一项更大的工作。为什么不简单地使用RecyclerView.addOnScrollListener并查看滚动达到了哪个位置,就像以下的Velval答案一样呢? - Bugs Happen
显示剩余7条评论

11
如果有人偶然看到这篇文章,这里有一个简单易懂的RecyclerView分页教程:
你只需要:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        int visibleItemCount        = lm.getChildCount();
        int totalItemCount          = lm.getItemCount();
        int firstVisibleItemPosition= lm.findFirstVisibleItemPosition();

        // Load more if we have reach the end to the recyclerView
        if ( (visibleItemCount + firstVisibleItemPosition) >= totalItemCount && firstVisibleItemPosition >= 0) {
            loadMoreItems();
        }
    }
});

那么你的loadMoreItems()应该长成这个样子:

private void loadMoreItems() {
    // init offset=0 the frist time and increase the offset + the PAGE_SIZE when loading more items
    queryOffset = queryOffset + PAGE_SIZE;
    // HERE YOU LOAD the next batch of items
    List<Items> newItems = loadItems(queryOffset, PAGE_SIZE);

    if (newItems.size() > 0) {
        items.addAll(newItems);
        adapter.notifyDataSetChanged();
    }
}

1
反过来呢? - sagar suri

0

0
看到了许多上面的答案,但我的答案不同,它也适用于您的情况。我的方法基于recylerview的滚动状态。维护下面的变量“check”,当api响应时,应该仅更新一次。将以下代码放入您的api响应中。如果您只想在每次调用api时处理最后一项。
final boolean[] check = {true};
    recyclerView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {
            if (!recyclerView.canScrollVertically(1)) {
                // last item of recylerview reached.
                if (check[0]) {
                    //your code for last reached item
                    scroll_handler.setVisibility(View.GONE);
                }
            } else {
                scroll_handler.setVisibility(View.VISIBLE);
                check[0] = false;
            }
        }
    });

如果您想每次处理最后一个项目,请按以下方式操作。
recyclerView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
    @Override
    public void onScrollChanged() {
        if (!recyclerView.canScrollVertically(1)) 
            // Bottom of recyler view.
            arrow_img.setRotation(180);
        }
    }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接