Reputation: 126
first question on StackOverflow!
I have an endlessly scrolling RecyclerView, preceded by several other views, all within a NestedScrollView.
Whenever I call findLastCompletelyVisibleItemPosition
on the RecyclerView's layout manager, I am given the position of the last element loaded in the RecyclerView...even if only the first one is visible on screen. I believe this is due to the fact that the RecyclerView is within a NestedScrollView -- the item is being displayed, however I'd have to scroll down to view it -- but I could definitely be wrong.
Initialization of RecyclerView in Fragment OnViewCreated :
@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//... irrelevant code ... //
photosRecyclerView = view.findViewById(R.id.profile_recyclerview_photos);
// Add LayoutManager to RecyclerView.
GridLayoutManager manager = new GridLayoutManager(getContext(), 2);
photosRecyclerView.setLayoutManager(manager);
// Smoothes scrolling from NestedScrollView.
photosRecyclerView.setNestedScrollingEnabled(false);
// Add adapter to RecyclerView.
profileRecyclerViewAdapter = new ProfileRecyclerViewAdapter(getContext(), photoList);
photosRecyclerView.setAdapter(profileRecyclerViewAdapter);
ScrollListener attached to RecyclerView :
private void initScrollListener() {
photosRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
final GridLayoutManager gridLayoutManager = (GridLayoutManager) recyclerView.getLayoutManager();
Log.d(TAG, "" + gridLayoutManager.findLastCompletelyVisibleItemPosition());
if (!loadingPhotos) {
if (gridLayoutManager.findLastCompletelyVisibleItemPosition() == photoList.size()-1 && hasMorePhotos) {
Log.d(TAG, "Attempting to load more images.");
loadMore();
loadingPhotos = true;
}
}
}
});
}
Layout of the Fragment :
<androidx.core.widget.NestedScrollView android:layout_height="match_parent"
android:layout_width="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimaryDark"
tools:context=".ProfileFragment">
<------- RANDOM OTHER VIEWS -------->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/profile_recyclerview_photos"
android:layout_marginTop="10dp"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@+id/profile_guideline_verticalstart"
app:layout_constraintEnd_toEndOf="@+id/profile_guideline_verticalend"
app:layout_constraintTop_toBottomOf="@id/profile_textview_photoslabel"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
Your help would be greatly appreciated!!
Upvotes: 6
Views: 2443
Reputation: 19
Had the same problem, I fixed my problem by detecting when nestedScrollView
is at the end!
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
if (isAnythingToLoad && rowsArrayList.size() > 8) {
//bottom of list!
loadMore();
}
}
}
}
})
Upvotes: 0
Reputation: 11
I recently faced an issue with recycler view, tried every possible solution but still failed. So I came up with this lightweight solution.
binding.currencies.apply {
adapter = currencyPagingAdapter
}.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
val lm = recyclerView.layoutManager as LinearLayoutManager
val lv = lm.getChildAt(lm.itemCount - 1)
val scrollBounds = Rect()
recyclerView.getHitRect(scrollBounds)
if (lv != null) {
if (lv.getLocalVisibleRect(scrollBounds)) {
Log.d("TAG", "onScrollStateChanged: visible")
} else {
Log.d("TAG", "onScrollStateChanged: not visible")
}
}
}
})
Upvotes: 1
Reputation: 41
You can try using constraint layout and change the recyclerview height to 0dp .
It will solve your problem
Upvotes: 4
Reputation: 126
After some research -- with a lot of help coming from this answer, I realized that this behaviour is due to the fact that the RecyclerView height is set to wrap content. This causes it to load all of the items immediately and thus the last "completely visible" item is the last item in the RecyclerView.
Upvotes: 5