Добавление элементов в Endless Scroll RecyclerView с помощью ProgressBar внизу

Я последовал за превосходным ответом Вилена на SO: Положите неопределенный прогресс в качестве нижнего колонтитула в сетке RecyclerView на том, как реализовать бесконечный прокрутки прокрутки с помощью ProgressBar.

Я реализовал его сам, и он работает, но я хотел бы расширить этот пример. Я хочу добавить дополнительные элементы в верхней части recyclerview, аналогично тому, как это делает 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 предметов загружаются, счетчик все еще существует:

После поворота

Что я делаю не так?

Solutions Collecting From Web of "Добавление элементов в Endless Scroll RecyclerView с помощью ProgressBar внизу"

Проблема в том, что когда вы добавляете новый элемент, внутренний EndlessRecyclerOnScrollListener не знает об этом и не EndlessRecyclerOnScrollListener счетчики. На самом деле ответ с EndlessRecyclerOnScrollListener имеет некоторые ограничения и возможные проблемы, например, если вы загружаете 1 элемент за раз, он не будет работать. Итак, вот расширенная версия.

  1. Избавьтесь от EndlessRecyclerOnScrollListener , он больше не нужен
  2. Измените адаптер на тот, который содержит прослушиватель прокрутки

     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. Изменить код в классе активности

     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); } 

Как только вы его добавите, код будет работать, однако вы увидите, что после того, как спиннер закончит вращение, номер позиции не будет увеличиваться правильно.

приращение

Это связано с тем, что элемент «Недавно добавленный» сверху считается как фактический элемент (мы можем назвать его «Item 0»), и это приводит к тому, что приращение смещения на 1, как 21, было пропущено, но на самом деле число 21 стало Item 0 Другими словами, перед пунктом 22 есть 21 фактический предмет.