I have one RecyclerView
and I added list of data into the RecyclerView
. I wanted to add more data in list, when last RecyclerView
item is
See also 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
}
If someone stumble across this post this is a quick and simple tutorial on how to do it:
All you need to do 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();
}
}
});
Then your loadMoreItems() should look something like this:
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();
}
}
One option would involve editing your LayoutManager
. The idea here is to find the position of the last visible item. If that position is equal to the last item of your dataset, then you should trigger a reload.
@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();
}
}
Alternatively, you could do this via your adapter's onBindViewHolder
method, although this is admittedly a bit of a "hack":
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (position == mData.length - 1) {
// load more data here.
}
/// binding logic
}
3rd option would be to add an OnScrollListener to the RecyclerView. @velval's answer on this page explains this well.
Regardless which option you go for, you should also include code to prevent the data load logic from triggering too many times (e.g., before the previous request to fetch more data completes and returns new data).
@Override
public void onBindViewHolder(final RecyclerView.ViewHolderholder, int position) {
if (!list.isEmpty() || list== null) {
if (position == (list.size() - 1)) {
// add new data (add data to list)
this.notifyDataSetChanged();
}
}
}
Seen many of the above answers but my answer is different one and it will work in your cases also. My approach is based on scroll state of recylerview. Maintain below variable "check" and this should update only once when api responds. Put below code in your api response. If you want to handle last item only on every call of 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;
}
}
});
If you want to handle your last item every time then do it as below
recyclerView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
if (!recyclerView.canScrollVertically(1))
// Bottom of recyler view.
arrow_img.setRotation(180);
}
}
});