Adding Items to Endless Scroll Recyclerview with Progressbar at Bottom

Adding items to Endless Scroll RecyclerView with ProgressBar at bottom

The problem is that when you add new item internal EndlessRecyclerOnScrollListener doesn't know about it and counters breaking.
As a matter of fact answer with EndlessRecyclerOnScrollListener has some limitations and possible problems, e.g. if you load 1 item at a time it will not work. So here is an enhanced version.

  1. Get rid of EndlessRecyclerOnScrollListener we don't need it anymore
  2. Change your adapter to this which contains scroll listener

    public class MyAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private final int VIEW_ITEM = 1;
    private final int VIEW_PROG = 0;

    private List<T> mDataset;

    // The minimum amount of items to have below your current scroll position before loading more.
    private int visibleThreshold = 2;
    private int lastVisibleItem, totalItemCount;
    private boolean loading;
    private OnLoadMoreListener onLoadMoreListener;

    public MyAdapter(List<T> myDataSet, RecyclerView recyclerView) {
    mDataset = myDataSet;

    if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {

    final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    super.onScrolled(recyclerView, dx, dy);

    totalItemCount = linearLayoutManager.getItemCount();
    lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
    if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
    // End has been reached
    // Do something
    if (onLoadMoreListener != null) {
    onLoadMoreListener.onLoadMore();
    }
    loading = true;
    }
    }
    });
    }
    }

    @Override
    public int getItemViewType(int position) {
    return mDataset.get(position) != null ? VIEW_ITEM : VIEW_PROG;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    RecyclerView.ViewHolder vh;
    if (viewType == VIEW_ITEM) {
    View v = LayoutInflater.from(parent.getContext())
    .inflate(android.R.layout.simple_list_item_1, parent, false);

    vh = new TextViewHolder(v);
    } else {
    View v = LayoutInflater.from(parent.getContext())
    .inflate(R.layout.progress_item, parent, false);

    vh = new ProgressViewHolder(v);
    }
    return vh;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if (holder instanceof TextViewHolder) {
    ((TextViewHolder) holder).mTextView.setText(mDataset.get(position).toString());
    } else {
    ((ProgressViewHolder) holder).progressBar.setIndeterminate(true);
    }
    }

    public void setLoaded() {
    loading = false;
    }

    @Override
    public int getItemCount() {
    return mDataset.size();
    }

    public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
    this.onLoadMoreListener = onLoadMoreListener;
    }

    public interface OnLoadMoreListener {
    void onLoadMore();
    }

    public static class TextViewHolder extends RecyclerView.ViewHolder {
    public TextView mTextView;

    public TextViewHolder(View v) {
    super(v);
    mTextView = (TextView) v.findViewById(android.R.id.text1);
    }
    }

    public static class ProgressViewHolder extends RecyclerView.ViewHolder {
    public ProgressBar progressBar;

    public ProgressViewHolder(View v) {
    super(v);
    progressBar = (ProgressBar) v.findViewById(R.id.progressBar);
    }
    }
    }
  3. Change code in Activity class

    mAdapter = new MyAdapter<String>(myDataset, mRecyclerView);
    mRecyclerView.setAdapter(mAdapter);

    mAdapter.setOnLoadMoreListener(new MyAdapter.OnLoadMoreListener() {
    @Override
    public void onLoadMore() {
    //add progress item
    myDataset.add(null);
    mAdapter.notifyItemInserted(myDataset.size() - 1);

    handler.postDelayed(new Runnable() {
    @Override
    public void run() {
    //remove progress item
    myDataset.remove(myDataset.size() - 1);
    mAdapter.notifyItemRemoved(myDataset.size());
    //add items one by one
    for (int i = 0; i < 15; i++) {
    myDataset.add("Item" + (myDataset.size() + 1));
    mAdapter.notifyItemInserted(myDataset.size());
    }
    mAdapter.setLoaded();
    //or you can add all at once but do not forget to call mAdapter.notifyDataSetChanged();
    }
    }, 2000);
    System.out.println("load");
    }
    });

The rest remains unchanged, let me know if this works for you.

Endless RecyclerView with ProgressBar for pagination

HERE IS SIMPLER AND CLEANER APPROACH.

Implement Endless Scrolling from this Codepath Guide and then follow the following steps.

1. Add progress bar under the RecyclerView.

    <android.support.v7.widget.RecyclerView
android:id="@+id/rv_movie_grid"
android:layout_width="0dp"
android:layout_height="0dp"
android:paddingBottom="50dp"
android:clipToPadding="false"
android:background="@android:color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

</android.support.v7.widget.RecyclerView>

<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
android:background="@android:color/transparent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

Here android:paddingBottom="50dp" and android:clipToPadding="false" are very important.

2. Get a reference to the progress bar.

progressBar = findViewById(R.id.progressBar);

3. Define methods to show and hide progress bar.

void showProgressView() {
progressBar.setVisibility(View.VISIBLE);
}

void hideProgressView() {
progressBar.setVisibility(View.INVISIBLE);
}

Endless RecyclerView with Progressbar at bottom

I haven't actually run the code, but at least this lines:

current_page++;
loadMore(current_page);
isLoading = true;

should be:

isLoading = true;
current_page++;
loadMore(current_page);

Certainly this must mess up the progress bar and the items since several loads can be launch concurrently.

Adding items to Endless Scroll RecyclerView with a ReverseLayout recyclerview

Simon: solution I previously proposed here works fine with reverse layout without any modification. The only thing I'd add for reverse layout is to scroll automatically to first item when you show it first time but that's up to you.
Now getting back to issue you have. You mentioned that when you scroll nothing happens. so my guess is that you initialize your recylcer view in a wrong order. Make sure you do it like this

mLayoutManager = new LinearLayoutManager(this);
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);

mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new MyAdapter<>(myDataset, mRecyclerView);
mRecyclerView.setAdapter(mAdapter);

Note that layout manager gets instantiated first, then you set it and after that you provide adapter. Let me know if that was the case.




Edit Just bringing up this from comment below:

forget about what we have with onLoadMoreListener and all scrolling stuff just use standard RecyclerView wrapped in SwipeToRefreshLayout

How to insert ProgressBar for loading more items in Recycler View?

a progress bar during the successive API call, which can be achieved using the android paging library.

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == DATA_VIEW_TYPE) NewsViewHolder.create(parent) else ListFooterViewHolder.create(retry, parent)
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (getItemViewType(position) == DATA_VIEW_TYPE)
(holder as NewsViewHolder).bind(getItem(position))
else (holder as ListFooterViewHolder).bind(state)
}

Based on the view type we can add the progress bar(indicate the next API call) at the end of the list.

please refer the https://medium.com/@sharmadhiraj.np/android-paging-library-step-by-step-implementation-guide-75417753d9b9

How to implement endless list with RecyclerView?

Thanks to @Kushal and this is how I implemented it

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

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) { //check for scroll down
visibleItemCount = mLayoutManager.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();

if (loading) {
if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
loading = false;
Log.v("...", "Last Item Wow !");
// Do pagination.. i.e. fetch new data

loading = true;
}
}
}
}
});

Don't forget to add

LinearLayoutManager mLayoutManager;
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);

Implementing Endless RecyclerView

This could achieve your goal.

public abstract class EndlessRecyclerOnScrollListener extends RecyclerView.OnScrollListener {
public static String TAG = EndlessRecyclerOnScrollListener.class.getSimpleName();

private int previousTotal = 0; // The total number of items in the dataset after the last load
private boolean loading = true; // True if we are still waiting for the last set of data to load.
private int visibleThreshold = 5; // The minimum amount of items to have below your current scroll position before loading more.
int firstVisibleItem, visibleItemCount, totalItemCount;

private int current_page = 1;

private LinearLayoutManager mLinearLayoutManager;

public EndlessRecyclerOnScrollListener(LinearLayoutManager linearLayoutManager) {
this.mLinearLayoutManager = linearLayoutManager;
}

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

visibleItemCount = recyclerView.getChildCount();
totalItemCount = mLinearLayoutManager.getItemCount();
firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();

if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
// End has been reached

// Do something
current_page++;

onLoadMore(current_page);

loading = true;
}
}

public abstract void onLoadMore(int current_page);
}

And sample activity

public class SampleActivity extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.list);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setOnScrollListener(new EndlessRecyclerOnScrollListener(linearLayoutManager) {
@Override
public void onLoadMore(int current_page) {
// do something...
}
});
}
}

Edit: See here: Endless Scrolling with AdapterViews

Endless RecyclerView with ProgressBar in Search activity

Add EndlessScrollListener to recyclerView from link:

https://gist.github.com/zfdang/38ae655a4fc401c99789#file-endlessrecycleronscrolllistener-java

override onLoadMore method and call your AsyncFetch Task.



Related Topics



Leave a reply



Submit