【问题标题】:How can I identify that RecyclerView's last item is visible on screen?如何确定 RecyclerView 最后一项在屏幕上可见?
【发布时间】:2020-08-07 21:42:48
【问题描述】:

我有一个RecyclerView,并将数据列表添加到RecyclerView。当最后一个RecyclerView 项目在屏幕上可见时,我想在列表中添加更多数据。之后,我想进行 Web 服务调用并更新 RecyclerView 数据。我怎样才能做到这一点?

有什么建议吗?

【问题讨论】:

  • 使用android.support.v7.widget.RecyclerView.OnScrollListener
  • 我知道滚动监听器,但我的问题是当用户在项目之间删除时,我怎么知道我的最后一个列表项是可见的,所以我可以更新列表或进行网络服务调用?
  • 然后使用onBindViewHolder
  • 如果position == getItemCount() - 1表示最后一项可见
  • 在 onBindViewHolder() 检查该位置是否是最后一个位置。如果是这样,请检查此 if (View.getVisibility() == View.VISIBLE)

标签: android android-recyclerview endlessscroll


【解决方案1】:

一种选择是编辑您的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 方法执行此操作,尽管这无疑有点“黑客”:

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

        /// binding logic
    }

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

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

【讨论】:

  • 我记得 recyclerview 将绑定更多的视图,它们将在屏幕外。所以,我认为检查最后一项可能没有帮助
  • 它会在视图即将变得可见时绑定它,所以我相信它对你来说应该足够好了。我将添加另一个选项
  • 是的,它将在即将变为可见时绑定。因此,绑定的最后一个不必已经可见。所以,我们仍然需要条件来检查可见性。他也可以在 LinearLayoutManager 中尝试 findLastVisibleItemPosition()。
  • 答案非常错误onBindViewHolder() 函数不能添加/加载数据。请不要使用这种技术。
  • 第一种方法是(请原谅我的语言)灾难,因为寻找更多数据不是onBindViewHolder 的工作。它应该只将数据绑定到ViewHolder。第二种方法更好一些,但是扩展LayoutManager 对于这样的小任务仍然是一项更大的工作。为什么不简单地使用 RecyclerView.addOnScrollListener 并查看滚动到达的位置,就像下面的 velval 答案一样。
【解决方案2】:

如果有人偶然发现这篇 this is 的帖子,一个快速简单的教程:

您需要做的就是:

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

【讨论】:

  • 反向呢?
【解决方案3】:

看过许多上述答案,但我的答案不同,它也适用于您的情况。我的方法是基于 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);
        }
    }
});

【讨论】:

    【解决方案4】:

    另见Android - Detect when the last item in a RecyclerView is visible

    private fun isLastItemVisible(): Boolean {
        val layoutManager = recycler_view.layoutManager
        val position = layoutManager.findLastCompletelyVisibleItemPosition()
        return position >= adapter.itemCount - 1
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-30
      • 2018-02-22
      • 2022-10-14
      • 2010-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-25
      相关资源
      最近更新 更多