RecyclerView / DiffUtils анимация при изменении набора данных без полного обновления - PullRequest
2 голосов
/ 28 марта 2020

Мне бы хотелось две вещи:

  • Чтобы не перезагружать / не обновлять sh адаптер, когда я удаляю элемент внутри RecyclerView (без использования notifyDatasetChanged).
  • Для этого я использую DiffUtils, который прекрасно работает. Но я также хотел бы сохранить DefaultItemAnimator из RecyclerView, который, по-видимому, не влияет на DiffUtils.

Поэтому мой вопрос: как я могу удалить / обновить элемент, не обновляя все набор данных И сохраняйте анимацию, аналогичную DefaultItemAnimator?

Я знаю, что многие посты дают ответы о RecyclerView, но ни один из них не соответствует моим потребностям. Я знаю о notifyItemRemoved, notifyItemRangeChanged, но они также обновляют sh весь набор данных.

Спасибо

EDIT , дающие некоторый код для лучшего понимания :

В моем адаптере я сделал два метода: Вот так я удаляю свое представление в указанной позиции c.

// Adapter methods
void removeAt(int position) {
     dataList.remove(position);
     recyclerView.removeViewAt(position);
     updateList(dataList);
     }

void updateList(ArrayList<MyModel> newList) {
     DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtilsTheme(oldList, newList));
     diffResult.dispatchUpdatesTo(this);
     }

А вот мой класс DiffUtils:

public class DiffUtils extends DiffUtil.Callback{

    ArrayList<MyModel> oldItems;
    ArrayList<MyModel> newItems;

    public DiffUtils(ArrayList<MyModel> newItems, ArrayList<MyModel> oldItems) {
        this.newItems = newItems;
        this.oldItems = oldItems;
    }

    /**
     *  It returns the size of the old list.
     * @return
     */
    @Override
    public int getOldListSize() {
        return oldItems.size();
    }

    /**
     * Returns the size of the new list;
     * @return
     */
    @Override
    public int getNewListSize() {
        return newItems.size();
    }

    /**
     * Called by the DiffUtil to decide whether two object represent the same Item.
     * Here we check the names because we know they are unique.
     * @param oldItemPosition
     * @param newItemPosition
     * @return
     */
    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        // We are sure that the names are unique
        return oldItems.get(oldItemPosition).getItemName().equals(newItem.get(newItemPosition).getItemName());
    }

    /**
     * Checks whether two items have the same data.
     * This method is called by DiffUtil only if areItemsTheSame returns true.
     * @param oldItemPosition
     * @param newItemPosition
     * @return
     */
    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        return oldItems.get(oldItemPosition).equals(newItems.get(newItemPosition));
    }

    /**
     * If areItemTheSame return true and areContentsTheSame returns false DiffUtil calls this method to get a payload about the change.
     * @param oldItemPosition
     * @param newItemPosition
     * @return
     */
    @Nullable
    @Override
    public Object getChangePayload(int oldItemPosition, int newItemPosition) {

        return super.getChangePayload(oldItemPosition, newItemPosition);
    }
}

Это удаляет элемент из списка, но без анимации. Мой RecyclerView также имеет ItemAnimator:

recyclerView.setItemAnimator(new DefaultItemAnimator());

Перед использованием класса DiffUtils я удалял вот так:

void removeAt(int position) {
     dataList.remove(position);
     notifyItemRemoved(position);
     notifyItemRangeChanged(position, dataList.size());
     }

Какой также работал и с анимацией, но обновлял все остальные элементы.

...