web-dev-qa-db-ja.com

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

その後、位置タグが正しくなくなり、DataSetChanged()に通知すると、派手なアニメーションが失われます。なにか提案を ?

29
elgui

いいえ、間違っています。まず、cannotメソッドが戻った後にonBindViewHolderに渡された位置への参照です。 RecyclerViewは、(アイテムの移動などにより)位置が変更されてもビューを再バインドしません。

代わりに、ViewHolder#getPosition()を使用して、更新された位置を返すことができます。

これを修正すると、ムーブコードが機能し、ニースのアニメーションが提供されるはずです。

notifyDataSetChangedを呼び出すと、予測アニメーションが妨げられるため、可能な限り避けてください。詳細については、 documentation を参照してください。

編集(コメントから):外部から位置を取得するには、recyclerviewから子ビューホルダーを取得し、vhから位置を取得します。詳細については、RecyclerView APIをご覧ください

5
yigit

notifyDataSetChanged()だけで派手なアニメーションを保持する方法があります

  1. GridLayoutManagerを返すsupportsPredictiveItemAnimations()メソッドをオーバーライドして、独自のtrueを作成する必要があります。

  2. mAdapter.setHasStableIds(true)する必要があります

  3. 私が扱いにくいと感じるのは、アダプターのgetItemId()メソッドをオーバーライドする必要があるということです。 positionの直接関数ではなく、真に一意の値を返す必要があります。 mItems.get(position).hashCode()のようなもの

私の場合は完璧に機能しました-notifyDataSetChanged()のみを使用してアイテムを追加、削除、移動するための美しいアニメーション

109
tochkov

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

}
3
Rahim Rahimov

メソッドをOnCreateViewHolderに移動すると、notifyItemRemoved(index)が適切に機能します。

0
Dominik

これをリストアイテムの外側の要素に追加することで、タッチアニメーションを維持できます。

<View
    Android:foreground="?android:attr/selectableItemBackground"
...>
0
fix