Добавление элементов в Endless Scroll RecyclerView с ProgressBar внизу
Я последовал за превосходным ответом Вилена на SO: поместите неопределенный индикатор выполнения в качестве нижнего колонтитула в сетку RecyclerView о том, как реализовать бесконечный просмотр повторного прокрутки с помощью ProgressBar.
Я реализовал это сам, и это работает, но я хотел бы расширить пример. Я хочу добавить дополнительные элементы в верхней части окна реселлера, подобно тому, как это делает Facebook, когда вы добавляете новое обновление статуса.
Я не смог успешно добавить дополнительные элементы в список - вот мой код, который я добавил в код Вилена в его MainActivity:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.add) {
myDataset.add(0, "Newly added");
mRecyclerView.smoothScrollToPosition(0);
mAdapter.notifyItemInserted(0);
}
return super.onOptionsItemSelected(item);
}
Когда я нажал кнопку "Добавить":
Когда я прокручиваю вниз, я получаю два счетчика вместо одного:
Когда счетчики заканчиваются и загружаются следующие 5 элементов, счетчик все еще там:
Что я делаю неправильно?
2 ответа
Проблема в том, что когда вы добавляете новый элемент внутри EndlessRecyclerOnScrollListener
не знает об этом и счетчики ломаются. На самом деле ответ с EndlessRecyclerOnScrollListener
имеет некоторые ограничения и возможные проблемы, например, если вы загружаете 1 элемент за раз, он не будет работать. Так что вот расширенная версия.
- Избавляться от
EndlessRecyclerOnScrollListener
нам это больше не нужно Измените свой адаптер на этот, который содержит слушателя прокрутки
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); } } }
Изменить код в классе деятельности
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"); } });
Остальное остается без изменений, дайте мне знать, если это работает для вас.
Я думаю, что я понял это.
Я забыл позвонить notifyItemRangeChanged.
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.add) {
myDataset.add(0, "Newly added");
mAdapter.notifyItemInserted(0);
mAdapter.notifyItemRangeChanged(1, myDataset.size());
mRecyclerView.smoothScrollToPosition(0);
}
return super.onOptionsItemSelected(item);
}
Как только вы добавите его, код будет работать, однако вы увидите, что после того, как прядильщик закончит вращение, номер элемента не будет увеличиваться должным образом.
Это потому, что "Недавно добавленный" элемент сверху считается как фактический элемент (мы можем назвать его "Элемент 0"), и это приводит к тому, что приращение смещения на 1, например, 21, было пропущено, но на самом деле число 21 стало Элементом 0. Другими словами, перед пунктом 22 есть 21 фактический предмет.