0

I have a recycleView that I need to observe when the last item is reached but I have notice the it always indicate that I reached the last item even if I haven't scrolled yet. My code for setting up the recycler:

newsRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
newsRecyclerView.setFocusable(false);
newsRecyclerView.setNestedScrollingEnabled(false);
newsAdapter = new NewsAdapter(getContext(), newsDetails, categoryNumber);
newsRecyclerView.setAdapter(newsAdapter);
layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);

My xml code is:

            <android.support.v7.widget.RecyclerView
            android:id="@+id/news_recycler_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="4dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/news_top_stories_title_text_view" />
Ali Habbash
  • 777
  • 2
  • 6
  • 29
  • Possible duplicate of [Detect when RecyclerView reaches the bottom most position while scrolling](https://stackoverflow.com/questions/36127734/detect-when-recyclerview-reaches-the-bottom-most-position-while-scrolling) – Manohar Aug 13 '18 at 06:08
  • you need to use `onScrollListener` on recyclerview and then find out last `((LinearLayoutManager) vYourRecycler.getLayoutManager()).findLastCompletelyVisibleItemPosition();` – Rahul Aug 13 '18 at 06:36

3 Answers3

1

This is my code that I put in my Util, and use anywhere.

Util.setRecyclerViewLastPositionListner(rv, linearLayoutManager , new UtilitiesV2.OnLastPositionReached() {
            @Override
            public void onReached() {
                // last position reached
            }
        });

Put this in Util.

 private boolean userScrolled = true;
    int pastVisiblesItems, visibleItemCount, totalItemCount;


    public interface OnLastPositionReached {
        void onReached();
    }

    public void setRecyclerViewLastPositionListner(RecyclerView rvBooksMockTest, final LinearLayoutManager mLayoutManager, final OnLastPositionReached onLastPositionReached) {
        rvBooksMockTest.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
                    userScrolled = true;
                }
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

                super.onScrolled(recyclerView, dx, dy);
                // Here get the child count, item count and visibleitems
                // from layout manager

                visibleItemCount = mLayoutManager.getChildCount();
                totalItemCount = mLayoutManager.getItemCount();
                pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();

                // Now check if userScrolled is true and also check if
                // the item is end then update recycler view and set
                // userScrolled to false
                if (userScrolled && (visibleItemCount + pastVisiblesItems) == totalItemCount) {
                    userScrolled = false;
                    if (onLastPositionReached != null) onLastPositionReached.onReached();
                }
            }
        });
    }

Update According to your requirement, here is NestedScrollView bottom reach listener.

nestedScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
    @Override
    public void onScrollChanged() {
        if (nestedScrollView != null) {
            if (nestedScrollView.getChildAt(0).getBottom() <= (nestedScrollView.getHeight() + nestedScrollView.getScrollY())) {
                //scroll view is at bottom
            } else {
                //scroll view is not at bottom
            }
        }
    }
});
Khemraj Sharma
  • 57,232
  • 27
  • 203
  • 212
0

Thanks to Khemraj who give the tip for solution because I have a recyclerview inside NestedScrollView and coordinator layout as parent for them

I have solved my problem like this:

public Disposable observeNestedScroll(LoadMoreListener listener) {
    return RxNestedScrollView.scrollChangeEvents(nestedScrollView)
            .subscribe(
                    viewScrollChangeEvent -> {
                        NestedScrollView nestedScrollView =(NestedScrollView) viewScrollChangeEvent.view();
                        if(nestedScrollView.getChildAt(nestedScrollView.getChildCount() - 1) != null) {
                            if ((viewScrollChangeEvent.scrollY() >= (nestedScrollView.getChildAt(nestedScrollView.getChildCount() - 1).getMeasuredHeight() - nestedScrollView.getMeasuredHeight())) &&
                                    viewScrollChangeEvent.scrollY() > viewScrollChangeEvent.oldScrollY()) {
                                listener.onLoadMore();
                            }
                        }
                    });
}
Ali Habbash
  • 777
  • 2
  • 6
  • 29
0

I've seen to many responses for this question and I stand that all of them don't give accurate behavior as an outcome. However if you follow this approach I'm positive you'll get the best behavior.

rvCategories is your RecyclerView

categoriesList is the list passed to your adapter

binding.rvCategories.addOnScrollListener(object : RecyclerView.OnScrollListener() {
      override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                val position = (recyclerView.layoutManager as LinearLayoutManager).findLastCompletelyVisibleItemPosition()
                if (position + 1 == categoriesList.size) {
                   // END OF RECYCLERVIEW IS REACHED
                } else {
                    // END OF RECYCLERVIEW IS NOT REACHED
                }
        }
    })
shady31
  • 101
  • 4