27

I have a method that will check if the last element in a RecyclerView is completely visible by the user, so far I have this code The problem is how to check if the RecyclerView has reached it's bottom ?

PS I have items dividers

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

UPDATE : This is one of the attempts I tried

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

so far no success I think there is something wrong within these lines :

int pos = layoutManager.findLastCompletelyVisibleItemPosition();
int numItems =  disp_adapter.getItemCount();
Thorvald Olavsen
  • 2,565
  • 3
  • 30
  • 50

4 Answers4

51

You can create a callback in your adapter which will send a message to your activity/fragment every time when the last item is visible.

For example, you can implement this idea in onBindViewHolder method

@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 
}

UPDATE

Well, I know it's been a while but today I ran into the same problem, and I came up with a solution that works perfectly. So, I'll just leave it here if anybody ever needs it:

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
        }
    }
});
nullbyte
  • 1,018
  • 8
  • 13
  • 2
    work only when the item get recycled... if the item is only two or three, the onBindViewHolder only called once when the items displayed first time, which mean the position check is only one times for each item. if we need to dynamically change something outside the items/recyclerview when scrolling, it will olny work at the first time. CMIIW – Hayi Nukman May 06 '17 at 06:20
  • 16
    @nullbyte why `+5` ? – Aniruddha Aug 09 '18 at 07:08
  • I also don't understand the meaning of +5 – viper Jul 01 '19 at 05:34
  • @viper try to debug. It will help you to understand that why it is five and why not 0. – Shahadat Hossain Feb 09 '20 at 08:00
  • why +5 in `boolean endHasBeenReached = lastVisible + 5 >= totalItemCount;` – Ravi Vaniya Apr 25 '20 at 14:25
  • Since the counting starts from 0 in this case, so I think we should do +1 and that worked in my case – Aakash Sharma May 21 '20 at 08:10
  • @RaviVaniya, I suppose, he has page size = 10 and performs pagination when scrolling. So, when RecyclerView reaches the last - 10/2 items, it will load the next page. – CoolMind Aug 07 '20 at 13:24
14

Assuming you're using LinearLayoutManager, this method should do the trick:

boolean isLastVisible() {
  LinearLayoutManager layoutManager = ((LinearLayoutManager)mRecyclerView.getLayoutManager());
  int pos = layoutManager.findLastCompletelyVisibleItemPosition();
  int numItems = mRecyclerView.getAdapter().getItemCount();
  return (pos >= numItems);
}
marmor
  • 25,207
  • 10
  • 99
  • 145
13

You should use your code with following change:

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

Be careful, findLastCompletelyVisibleItemPosition() returns the position which start at 0. So, you should minus 1 after numItems.

Vadim Kotov
  • 7,103
  • 8
  • 44
  • 57
Richard
  • 201
  • 2
  • 7
3

try working with onScrollStateChanged it will solve your issue

Michael
  • 8,464
  • 2
  • 59
  • 62
Metronom
  • 216
  • 1
  • 14