Android - 检测RecyclerView中最后一个项目何时可见

39
我有一个方法可以检查用户是否完全看到了RecyclerView中的最后一个元素,迄今为止我有以下代码。问题是如何检查RecyclerView是否已经滑动到底部?

PS:我的RecyclerView有项分隔符。
public void scroll_btn_visibility_controller(){
    if(/**last item is visible to user*/){
        //This is the Bottom of the RecyclerView
        Scroll_Top_Btn.setVisibility(View.VISIBLE);
    }
    else(/**last item is not visible to user*/){
        Scroll_Top_Btn.setVisibility(View.INVISIBLE);
    }
}

更新:这是我尝试过的其中一种方法

boolean isLastVisible() {
    LinearLayoutManager layoutManager = ((LinearLayoutManager)rv.getLayoutManager());
    int pos = layoutManager.findLastCompletelyVisibleItemPosition();
    int numItems =  disp_adapter.getItemCount();
    return (pos >= numItems);
}
public void scroll_btn_visibility_controller(){

    if(isLastVisible()){
        Scroll_Top.setVisibility(View.VISIBLE);
    }
    else{
        Scroll_Top.setVisibility(View.INVISIBLE);
    }
} 

到目前为止没有成功,我认为这些行中有些地方出了问题:

int pos = layoutManager.findLastCompletelyVisibleItemPosition();
int numItems =  disp_adapter.getItemCount();

你有什么问题? - Real73
@Real73 我完全不知道如何去做! - Thorvald
可能是获取RecyclerView中可见项的重复问题。 - Acapulco
7个回答

62

您可以在适配器中创建一个回调函数,在最后一项可见时向您的活动/片段发送消息。

例如,您可以在onBindViewHolder方法中实现此想法。

@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
    if(position==(getItemCount()-1)){
        // here goes some code
        //  callback.sendMessage(Message);
     }
    //do the rest of your stuff 
}

更新

虽然已经有一段时间了,但今天我又遇到了同样的问题,并找到了一个完美解决方案。因此,我将在这里分享出来,以便未来需要的人可以参考:

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        LinearLayoutManager layoutManager=LinearLayoutManager.class.cast(recyclerView.getLayoutManager());
        int totalItemCount = layoutManager.getItemCount();
        int lastVisible = layoutManager.findLastVisibleItemPosition();

        boolean endHasBeenReached = lastVisible + 5 >= totalItemCount;
        if (totalItemCount > 0 && endHasBeenReached) {
            //you have reached to the bottom of your recycler view
        }
    }
});

2
只有当项目被回收时才能工作...如果项目只有两个或三个,那么当项目首次显示时 onBindViewHolder 只会被调用一次,这意味着每个项目的位置检查仅一次。 如果我们需要在滚动时动态更改 items/recyclerview 外部的某些内容,则仅第一次会起作用。请纠正我如果我错了。 - Hayi Nukman
19
@nullbyte 为什么是 +5 - Aniruddha
我也不理解+5的含义。 - viper
由于在这种情况下计数从0开始,所以我认为我们应该加1,这在我的情况下起作用了。 - Aakash Sharma
@RaviVaniya,我猜他的页面大小为10,并在滚动时执行分页。因此,当RecyclerView到达最后的10/2项时,它将加载下一页。 - CoolMind
显示剩余2条评论

18

您应该使用以下更改后的代码:

boolean isLastVisible() {
    LinearLayoutManager layoutManager =((LinearLayoutManager) rv.getLayoutManager());
    int pos = layoutManager.findLastCompletelyVisibleItemPosition();
    int numItems = rv.getAdapter().getItemCount();
    return (pos >= numItems - 1);
}

注意,findLastCompletelyVisibleItemPosition()返回从0开始的位置。因此,在计算numItems后应该减去1。


2
这实际上是正确的isLastVisible方法,与先前的isLastVisible方法答案相比。 - debo.stackoverflow
2
谢谢!这对我来说是最好和最简单的解决方案。 - Erkan

15
假设你正在使用LinearLayoutManager,这个方法应该可以解决问题:
boolean isLastVisible() {
  LinearLayoutManager layoutManager = ((LinearLayoutManager)mRecyclerView.getLayoutManager());
  int pos = layoutManager.findLastCompletelyVisibleItemPosition();
  int numItems = mRecyclerView.getAdapter().getItemCount();
  return (pos >= numItems);
}

重新构建应用程序后,应用程序不会崩溃,也不会出现任何错误,但是该方法无效,当我到达结尾时,可见性不会更改为“VISIBLE”。 - Thorvald
将您获取的“pos”和“numItems”的值打印到日志中,并尝试理解问题。此外,请确保在适当的时间调用该方法。 - marmor
4
为了得到正确的结果,我不得不将pos的数量增加1个。否则,它会为所有结果提供false - Prashant Kumar Sharma
1
请参见下面的答案:return (pos >= numItems - 1); - debo.stackoverflow

5

尝试使用onScrollStateChanged,它可以解决你的问题。


0

尝试这个解决方案,因为它取决于您想要实现聊天的方式。

在您的onCreate()方法中添加调用以将内容发布到您的recyclerview并实现runable方法,以确保元素已经加载,然后执行scrollToPosition方法,并将您列表的最后一个元素作为参数添加。

recyclerView.post(new Runnable() {
   @Override
   public void run() {
      recyclerView.scrollToPosition(yourList().size()-1);
   }
});

0
在另一种使用LayoutManager的方法中,您可以保存第一个可见位置,然后使用notifyDataSetChanged()通知所有项目,最后滚动到保存的位置-1。请看下面的Kotlin代码:
val targetScrolledPosition = layoutManager.findFirstVisibleItemPosition() - 1
adapter.items.removeAt(position)
adapter.notifyDataSetChanged()
if(targetScrolledPosition >= 0)
   layoutManager.scrollToPosition(targetScrolledPosition)

但从性能方面来看,如果行数很多,我认为这是一个坏主意。


0

为了确定RecyclerView的最后一个项目何时可见,以便隐藏或显示按钮,您可以使用RecyclerView的addOnScrollListener方法。以下是使用Kotlin的示例实现:

recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)

        val layoutManager = recyclerView.layoutManager as LinearLayoutManager
        val lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition()
        val totalItemCount = layoutManager.itemCount

        // Check if the last visible item is the last item in the list
        val isLastItemVisible = lastVisibleItemPosition == totalItemCount - 1

        // Show or hide the button based on the visibility of the last item
        if (isLastItemVisible) {
            btnScrollToTop.visibility = View.VISIBLE
        } else {
            btnScrollToTop.visibility = View.GONE
        }
    }
})

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