findLastVisibleItemPosition is returning wrong value if RecyclerView inside NestedScrollView

findLastVisibleItemPosition is returning wrong value if RecyclerView inside NestedScrollView



I have RecyclerView inside NestedScrollView


<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v7.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</android.support.v4.widget.NestedScrollView>



I have this problem in big project and in order to find solution for this problem I have created new project without other views.



This is full code of MainActivity


class MainActivity : AppCompatActivity()

var mItems = mutableListOf<String>()
var mAdapter = MyAdapter(mItems)

override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

recycler.layoutManager = LinearLayoutManager(this)
recycler.adapter = mAdapter

delayedLoadDataIfPossible(100)

recycler.viewTreeObserver.addOnScrollChangedListener
delayedLoadDataIfPossible(100)




private fun delayedLoadDataIfPossible(delay: Long)
Observable.timer(delay, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe
var scrollingReachedEnd = isScrollingReachedEnd()
if (scrollingReachedEnd)
loadData()




private fun isScrollingReachedEnd(): Boolean
val layoutManager = LinearLayoutManager::class.java.cast(recycler.layoutManager)
val totalItemCount = layoutManager.itemCount
val lastVisible = layoutManager.findLastVisibleItemPosition()
return lastVisible + 5 >= totalItemCount


private fun loadData()
Observable.timer(5, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe progress.visibility = View.VISIBLE
.doFinally progress.visibility = View.GONE
.subscribe
for (i in 1..10)
mItems.add(i.toString())

mAdapter.notifyDataSetChanged()
delayedLoadDataIfPossible(100)







I am using isScrollingReachedEnd method to identify is scrolling reaching end of list. If there are less than 5 visible items in the end, I am trying to load new data.



loadData simulates loading data. It adds 10 items to list and notifies adapter about change.



delayedLoadDataIfPossible method should work after some delay because findLastVisibleItemPosition is returning value before items are added to list. In result it is returning wrong value. For example -1 after adding first 10 items.



My problem: when RecyclerView inside NestedScrollView findLastVisibleItemPosition returning wrong value and data loading can not be stopped even there are enough items. There is no such problem when RecyclerView not inside NestedScrollView.



My question: how to get last visible item position from RecyclerView when it is inside NestedScrollView?






have u set recyclerView.setNestedScrollingEnabled(false);

– Nilesh Rathod
Sep 7 '18 at 8:11


recyclerView.setNestedScrollingEnabled(false);






have u used findOneVisibleChild(layoutManager.getChildCount() - 1, -1, false, true)

– Ashvin solanki
Sep 7 '18 at 8:14






@NileshRathod I have tried to set nestedScrollingEnabled false but it did not help

– Joe Rakhimov
Sep 7 '18 at 9:30






Is this the issue?

– Cheticamp
Sep 11 '18 at 19:12






I would actually put those "above" views right into the RecyclerView itself. It means that the adapter has to manage that data, which can interfere with separation of concerns; however it gets the job done. Now you didn't post your entire activity layout with all the included layouts so I don't know if the approach is appropriate. Post more layouts and code, then I might be able to answer this for you. List models do not have to be homogeneous. Consider that the RecyclerView.Adapter has the getItemViewType() method so you can inflate different views based on the item position.

– kris larson
Sep 13 '18 at 13:11


RecyclerView


RecyclerView.Adapter


getItemViewType()




2 Answers
2



You could try this approach:



This is my code for a ScrollingListener for a NestedScrollingView:


@Override
public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY)

int lastVisibleItemPosition = 0;
int totalItemCount = layoutManager.getItemCount();

if(v.getChildAt(v.getChildCount() - 1) != null)
if (scrollY >= (v.getChildAt(v.getChildCount()-1).getMeasuredHeight() - v.getMeasuredHeight())
&& scrollY > oldScrollY)
if (layoutManager instanceof LinearLayoutManager)
lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();


if (totalItemCount < previousTotalItemCount)
this.currentPage = this.startingPageIndex;
this.previousTotalItemCount = totalItemCount;
if (totalItemCount == 0)
this.loading = true;



if (loading && (totalItemCount > previousTotalItemCount))
loading = false;
previousTotalItemCount = totalItemCount;


if (!loading && (lastVisibleItemPosition + visibleThreshold) > totalItemCount)
currentPage++;
onLoadMore();
loading = true;






Good luck!



If your RecyclerView is inside a NestedScrollView, you need to add recyclerView.setNestedScrollingEnabled(false) to it.


RecyclerView


NestedScrollView


recyclerView.setNestedScrollingEnabled(false)



Also another note (which is unrelated to your question is that you should definitely keep a reference to those RxJava subscriptions and dispose them on Fragment/Adtivity's onStop, since they can cause memory leak issues.



Thanks for contributing an answer to Stack Overflow!



But avoid



To learn more, see our tips on writing great answers.



Required, but never shown



Required, but never shown




By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)