Подтвердить что ты не робот

Адаптер RecyclerView notifyDataSetChanged останавливает причудливую анимацию

Я создаю компонент на основе RecyclerView, позволяя пользователю переупорядочивать элементы путем перетаскивания. Когда я нахожусь на стороне DragListener, мне нужно положение, которое у него есть в адаптере, чтобы выполнить правильный ход, но у меня есть только доступ к представлению. Итак, вот что я делаю в привязке вида адаптера:

@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
    Track track = mArray.get(position);
    viewHolder.itemView.setTag(R.string.TAG_ITEM_POSITION, position);
}

Это кажется вам правильным? Потому что, если я перемещаю элемент следующим образом:

public void move(int from, int to){
    Track track = mArray.remove(from);
    mArray.add(to, track);
    notifyItemMoved(from, to);
}

тогда тег позиции больше не подходит, и если я notifyDataSetChanged(), я теряю причудливую анимацию. Любое предложение?

4b9b3361

Ответ 1

Нет, это неправильно. Прежде всего, вы не можете ссылаться на позицию, переданную onBindViewHolder после того, как этот метод вернется. RecyclerView не будет перепроверять представление, когда его позиция изменяется (из-за перемещения элементов и т.д.).

Вместо этого вы можете использовать ViewHolder#getPosition(), который вернет вам обновленную позицию.

Если вы исправите это, ваш код перехода должен работать и обеспечивать приятную анимацию.

Вызов notifyDataSetChanged предотвратит предсказательную анимацию, поэтому избегайте ее, насколько сможете. Подробнее см. .

Изменить (из комментария): чтобы получить позицию извне, получить дочерний элемент просмотра от recyclerview, а затем получить позицию из vh. Подробнее см. В разделе RecyclerView api.

Ответ 2

Существует способ сохранить фантастические анимации только с notifyDataSetChanged()

  • Вам нужно сделать свой собственный GridLayoutManager с помощью метода overrideen supportsPredictiveItemAnimations(), возвращающего true;

  • Вам нужно mAdapter.setHasStableIds(true)

  • Часть, которую я считаю сложной, - вам нужно переопределить ваш адаптер getItemId(). Он должен возвращать значение, которое действительно уникально, а не прямая функция position. Что-то вроде mItems.get(position).hashCode()

Работала отлично в моем случае - красивые анимации для добавления, удаления и перемещения элементов только с помощью notifyDataSetChanged()

Ответ 3

1) Для анимации вы будете использовать notifyItemInserted(position); или notifyItemRemoved(position); вместо notifyDataSetChanged(). 2) Вы можете вручную исправить свою проблему - используя

public void move(int from, int to){
    Track track = mArray.remove(from);
    mArray.add(to, track);
    notifyItemMoved(from, to);
    ViewHolder fromHolder = (ViewHolder) mRecyclerView.findViewHolderForPosition(from);
    ViewHolder toHolder = (ViewHolder) mRecyclerView.findViewHolderForPosition(to);
    Tag fromTag = fromHolder.itemView.getTag();
    fromHolder.itemView.setTag(toHolder.itemView.getTag()); 
    toHolder.itemView.setTag(fromTag);

}

Ответ 4

Вы должны переместить свой метод на OnCreateViewHolder, затем notifyItemRemoved(index) работает правильно.