Адаптер 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(), я теряю причудливую анимацию.
Любое предложение?
Ответы
Ответ 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)
работает правильно.