Skip to content

Instantly share code, notes, and snippets.

@DFreds
Created November 27, 2018 18:33
Show Gist options
  • Save DFreds/1fbf9b6ce699454713ab157ec8bad3be to your computer and use it in GitHub Desktop.
Save DFreds/1fbf9b6ce699454713ab157ec8bad3be to your computer and use it in GitHub Desktop.
EndlessScrollListener implementation
package com.upmc.enterprises.myupmc
import android.support.v7.widget.GridLayoutManager
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.StaggeredGridLayoutManager
abstract class EndlessRecyclerViewScrollListener(
private val layoutManager: RecyclerView.LayoutManager,
private val indexDelta: Int = 20
) : RecyclerView.OnScrollListener() {
// The minimum amount of items to have below your scroll position before loading more
private var visibleThreshold = 5
// The current offset index of data you have loaded
private var currentIndex = 0
// The total number of items in the data set after the last load
private var previousTotalItemCount = 0
// True if we are still waiting for the last set of data to load
private var loading = true
// Sets the starting page index
private val startingPageIndex = 0
init {
when (layoutManager) {
is StaggeredGridLayoutManager -> {
visibleThreshold *= layoutManager.spanCount
}
is GridLayoutManager -> {
visibleThreshold *= layoutManager.spanCount
}
}
}
abstract fun doneLoading()
abstract fun onLoadMore(currentIndex: Int, totalItemsCount: Int, view: RecyclerView)
// This happens many times a second during a scroll, so be wary of the code you place here.
// We are given a few useful parameters to help us work out if we need to load some more data,
// but first we check if we are waiting for the previous load to finish.
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
// ignore scrolling up
if (dy <= 0) return
val totalItemCount = this.layoutManager.itemCount
val lastVisibleItemPosition = when (layoutManager) {
is StaggeredGridLayoutManager -> {
val lastVisibleItemPositions = layoutManager.findLastVisibleItemPositions(null)
// get maximum element within the list
getLastVisibleItem(lastVisibleItemPositions)
}
is GridLayoutManager -> layoutManager.findLastVisibleItemPosition()
is LinearLayoutManager -> layoutManager.findLastVisibleItemPosition()
else -> 0
}
// If the total item count is zero and the previous isn't, assume the
// list is invalidated and should be reset back to initial state
if (totalItemCount < previousTotalItemCount) {
this.currentIndex = this.startingPageIndex
this.previousTotalItemCount = totalItemCount
if (totalItemCount == 0) {
this.loading = true
}
}
// If it’s still loading, we check to see if the dataset count has
// changed, if so we conclude it has finished loading and update the current page
// number and total item count.
if (loading && (totalItemCount > previousTotalItemCount)) {
loading = false
doneLoading()
previousTotalItemCount = totalItemCount
}
// If it isn’t currently loading, we check to see if we have breached
// the visibleThreshold and need to reload more data.
// If we do need to reload some more data, we execute onLoadMore to fetch the data.
// threshold should reflect how many total columns there are too
if (!loading && (lastVisibleItemPosition + visibleThreshold) > totalItemCount) {
currentIndex += indexDelta
onLoadMore(currentIndex, totalItemCount, recyclerView)
loading = true
}
}
fun getLastVisibleItem(lastVisibleItemPositions: IntArray): Int {
var maxSize = 0
lastVisibleItemPositions.forEach {
if (it == 0) {
maxSize = lastVisibleItemPositions[it]
} else if (lastVisibleItemPositions[it] > maxSize) {
maxSize = lastVisibleItemPositions[it]
}
}
return maxSize
}
// Call this method whenever performing new searches
fun resetState() {
this.currentIndex = this.startingPageIndex
this.previousTotalItemCount = 0
this.loading = true
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val layoutManager = LinearLayoutManager(context)
recyclerView?.addItemDecoration(DividerItemDecoration(recyclerView?.context, DividerItemDecoration.VERTICAL))
recyclerView?.adapter = adapter
recyclerView?.layoutManager = layoutManager
recyclerView?.addOnScrollListener(object : EndlessRecyclerViewScrollListener(layoutManager) {
override fun doneLoading() {
Logger.d("Finished loading more")
}
override fun onLoadMore(currentIndex: Int, totalItemsCount: Int, view: RecyclerView) {
Logger.d("On load more $currentIndex, $totalItemsCount")
// load more with the current index
}
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment