Reputation: 954
Recyclerview
comes with its own scroll listener which has the following methods :
void onScrollStateChanged(RecyclerView recyclerView, int newState)
Callback method to be invoked when RecyclerView's scroll state changes.
void onScrolled(RecyclerView recyclerView, int dx, int dy)
Callback method to be invoked when the RecyclerView has been scrolled.
Is there any way to trigger loader to load more data when scroll reaches end of the list?
I have implemented this way:
@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
GenerItem generItem=generItems.get(i);
Log.d("TAG","position "+i);
if(i==generItems.size()-1)
((GenerSearchActivity)mContext).onScroll(i);
viewHolder.bindValues(generItem);
}
Here onScroll()
in Activity, will trigger the loader to load more data. What is the best way please suggest.
Upvotes: 3
Views: 9106
Reputation: 18192
There are essentially 3 steps.
But first, we need a Callback which would work as a bridge between RecyclerView.Adapter and Activity
public interface PaginationCallBack{
public void oadNextPage();
}
Implement this callback in Your Activity
class YourActivity extends AppCompatActivity implements PaginationCallBack{
int pageNum = 1;
@Override
public void loadNextPage(){
// Your implementation
}
}
Initialize Callback in RecyclerView.Adapter
class YourAdapter extends RecyclerView.Adapter{
private PaginationCallBack paginationCallBack;
public YourAdapter(PaginationCallBack paginationCallBack) {
this.paginationCallBack = paginationCallBack;
}
}
STEP 1
Add a condition in onBindViewHolder
method and notify with a Callback.
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewholder, int position) {
if(position+1==images.size()){
paginationCallBack.loadNextPage(); // Callback
}
}
Step 2: Call NEXT Page
getImages(++pageNum) // YOUR REST method which page number
@Override
public void loadNextPage(){
getImages(++pageNumber) // REST call with next Page
}
Step 3 Add the result in old list and notify datasetChanged
public void getImages(int pageNum){
List<Images> newResults = //RESTCALL
imageList.addAll(newResults);
adapter.updateDataSet(imageList)
}
updateDataSet(imageList)
method?Write this method inside RecyclerView.Adapter
public void updateDataSet(List<GalleryMedia> newImages){
if(newImages!=null){
images = newImages;
}
notifyDataSetChanged();
}
Upvotes: 2
Reputation: 11921
Here's a scroll listener which implements load more and quick return pattern:
public abstract class HidingScrollListener extends RecyclerView.OnScrollListener {
private static final float HIDE_THRESHOLD = 10;
private static final float SHOW_THRESHOLD = 70;
private int mToolbarOffset = 0;
private boolean mControlsVisible = true;
private int mToolbarHeight;
private int mTotalScrolledDistance;
private int previousTotal = 0;
private boolean loading = true;
private int visibleThreshold = 4;
int firstVisibleItem, visibleItemCount, totalItemCount;
private LinearLayoutManager layoutManager;
public HidingScrollListener(Context context, LinearLayoutManager layoutManager) {
mToolbarHeight = Tools.getFooterHeight(context);
this.layoutManager = layoutManager;
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (mTotalScrolledDistance < mToolbarHeight) {
setVisible();
}
else {
if (mControlsVisible) {
if (mToolbarOffset > HIDE_THRESHOLD) {
setInvisible();
}
else {
setVisible();
}
}
else {
if ((mToolbarHeight - mToolbarOffset) > SHOW_THRESHOLD) {
setVisible();
}
else {
setInvisible();
}
}
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
clipToolbarOffset();
onMoved(mToolbarOffset);
if ((mToolbarOffset < mToolbarHeight && dy > 0) || (mToolbarOffset > 0 && dy < 0)) {
mToolbarOffset += dy;
}
if (mTotalScrolledDistance < 0) {
mTotalScrolledDistance = 0;
}
else {
mTotalScrolledDistance += dy;
}
// for load more
visibleItemCount = recyclerView.getChildCount();
totalItemCount = layoutManager.getItemCount();
firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
// End has been reached
// Do something
loading = true;
onLoadMore();
}
}
private void clipToolbarOffset() {
if (mToolbarOffset > mToolbarHeight) {
mToolbarOffset = mToolbarHeight;
}
else if (mToolbarOffset < 0) {
mToolbarOffset = 0;
}
}
private void setVisible() {
if (mToolbarOffset > 0) {
onShow();
mToolbarOffset = 0;
}
mControlsVisible = true;
}
private void setInvisible() {
if (mToolbarOffset < mToolbarHeight) {
onHide();
mToolbarOffset = mToolbarHeight;
}
mControlsVisible = false;
}
public abstract void onMoved(int distance);
public abstract void onShow();
public abstract void onHide();
public abstract void onLoadMore();
}
And it's implementation is below:
HidingScrollListener scrollListener = new HidingScrollListener(activity, manager) {
@Override
public void onMoved(int distance) {
}
@Override
public void onShow() {
}
@Override
public void onHide() {
}
@Override
public void onLoadMore() {
// you can do your pagination here.
}
};
mRecyclerView.addOnScrollListener(scrollListener);
Upvotes: 0