Keine Animation beim Entfernen von Artikeln in RecyclerView

Lesezeit: 5 Minuten

Benutzer-Avatar
Jordi Chacon

ich benutze RecyclerView zum ersten Mal. Alles funktioniert gut, außer dass es keine Animation beim Entfernen von Gegenständen gibt, obwohl die Animation beim Hinzufügen von Gegenständen einwandfrei funktioniert.

Ich habe keinen benutzerdefinierten Item-Animator eingestellt, aber nach dem Dokumentation:

Animationen zum Hinzufügen und Entfernen von Elementen sind standardmäßig in aktiviert RecyclerView.

Die Animationen zum Entfernen sollten also funktionieren.

Ich hätte gerne die Standardanimation beim Entfernen, kann das aber nicht zum Laufen bringen.

So richte ich RecyclerView ein:

private void setupRecyclerView() {
  mRecyclerView = (RecyclerView) mRootView.findViewById(R.id.recycler_view);
  mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
  View emptyView = mRootView.findViewById(R.id.empty_view);
  mAdapter = new RoutineAdapter(getActivity(), mRoutineItems, emptyView);
  mRecyclerView.setAdapter(mAdapter);
}

Das ist mein Adapter:

private class RoutineAdapter
      extends RecyclerView.Adapter<RoutineAdapter.ViewHolder> {

private final Context mContext;
private List<RoutineItem> mData;
private View mEmptyView;

    public RoutineAdapter(Context context, List<RoutineItem> data, View emptyView) {
      mContext = context;
      mData = data;
      mEmptyView = emptyView;
      setEmptyViewVisibility();
    }

    public void add(RoutineItem routineItem, int position) {
      mData.add(position, routineItem);
      setEmptyViewVisibility();
      notifyItemInserted(position);
    }

    public void remove(int position){
      mData.remove(position);
      setEmptyViewVisibility();
      notifyItemRemoved(position);
    }

    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
      final View view = LayoutInflater.from(mContext).inflate(
          R.layout.fragment_routines_list_item, parent, false);
      return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
      final RoutineItem routineItem = getItem(position);
      holder.circle.setBackgroundResource(
          colorNumberToDrawableResource(routineItem.colorNumber));
      holder.initial.setText(routineItem.routineName.substring(0, 1));
      holder.routineName.setText(routineItem.routineName);
      holder.lastTimeDone.setText(routineItem.lastTimeDoneText);
      if (routineItem.isSelected) {
        holder.itemView.setBackgroundColor(
            getResources().getColor(R.color.background_item_selected));
      } else {
        holder.itemView.setBackgroundResource(
            R.drawable.darker_background_on_pressed);
      }
      holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
          mPresenter.onRoutineClicked(routineItem.routineName);
        }
      });
      holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
          mPresenter.onRoutineLongClicked(routineItem.routineName);
          return true;
        }
      });
    }

    @Override
    public int getItemCount() {
      return mData.size();
    }

    public RoutineItem getItem(int position) {
      return mData.get(position);
    }

    private void setEmptyViewVisibility() {
      if (getItemCount() == 0) {
        mEmptyView.setVisibility(View.VISIBLE);
      } else {
        mEmptyView.setVisibility(View.GONE);
      }
    }

    class ViewHolder extends RecyclerView.ViewHolder {
      public final View circle;
      public final TextView initial;
      public final TextView routineName;
      public final TextView lastTimeDone;

      public ViewHolder(View view) {
        super(view);
        circle = view.findViewById(R.id.circle);
        initial = (TextView) view.findViewById(R.id.initial);
        routineName = (TextView) view.findViewById(R.id.routine_name);
        lastTimeDone = (TextView) view.findViewById(R.id.last_time_done);
      }
    }
}

Fragment_routines_list_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:minHeight="@dimen/standard_list_item_height"
  android:paddingBottom="8dp"
  android:background="@drawable/darker_background_on_pressed"
  android:clickable="true">
    ......
</RelativeLayout>

Was mache ich falsch, dass die standardmäßige Entfernungsanimation nicht funktioniert?

Der richtige Weg, ein Element aus der Recycler-Ansicht zu entfernen, besteht darin, das Element aus dem Datensatz zu entfernen und dann dem Adapter mitzuteilen, dass das Element so entfernt wurde

myDataset.remove(position); // myDataset is List<MyObject>
mAdapter.notifyItemRemoved(position);

Benutzer-Avatar
Jordi Chacon

Ich habe es gelöst.

Das Problem war, dass nach dem Anruf mAdapter.remove(position)ein anderer Teil meines Codes rief an mAdapter.notifyDataSetChanged() was ich annehme stoppt die Entfernungsanimation.

Zusammenfassend, wenn Sie anrufen mAdapter.notifyDataSetChanged Während eine Animation läuft, stoppt die Animation.

  • Und Indizes werden durcheinander gebracht, wenn Sie dies nicht tun.

    – Milosmen

    5. August 2015 um 17:45 Uhr

  • Die Lösung zur Behebung dieses Problems besteht darin, viewHolder.getAdapterPosition() für onClick anstelle der Position zu verwenden, die innerhalb von onBindViewHolder übergeben wird

    – MobilMon

    24. Oktober 2015 um 19:31 Uhr

Verwenden notifyItemRemoved(position) Anstatt von notifyDataSetChanged() Wie unten

myDataset.remove(position);
notifyItemRemoved(position);

Weil notifyDataSetChanged() benachrichtigt einfach die aktualisierten Daten ohne Animationen.

  • aber der Adapter verliert Positionen anderer Elemente in der Liste und wenn Sie versuchen, ein anderes Element zu löschen, wird es das Element darunter entfernen, auch wenn es kein Element darunter gibt, dann stürzt es ab. Bitte bestätigen Sie das.

    – Wales

    23. Dezember 2018 um 10:28 Uhr

  • myDataset.remove (Position); benachrichtigenItemRemoved(position); benachrichtigenItemRangeChanged(position, youDataSets.size()); Verwenden Sie diesen Code, dies wird Ihr Problem lösen.

    – Kalanar

    20. April 2019 um 15:24 Uhr


Ich konnte die Ansicht mit der Animation und den aktualisierten Indizes wie folgt entfernen:

Innerhalb des Adapters

public boolean removeItem(int position) {
    if (data.size() >= position + 1) {
        data.remove(position);
        return true;
    }
    return false;
}

Rufen Sie beim Entfernen der Ansichten an

if (adapter.removeItem(position)) {
    adapter.notifyItemRemoved(position);
    adapter.notifyItemRangeChanged(position, adapter.getItemCount());
}

Ich habe eine boolesche Methode verwendet, um sicherzustellen, dass Doppelklicks usw. keinen Absturz verursachen.

Nach langem Debuggen wurde mir klar, dass ich hinzufügen musste setHasStableIds(true) zu meinem Adapter und implementieren

@Override
public long getItemId(int position) {
    return position;
}

Danach begann die Animation zum Entfernen zu funktionieren

Benutzer-Avatar
Benutzer1185087

Ein weiterer Grund für eine nicht richtig funktionierende Entfernen-Animation könnte die sein RecyclerViews Höhe. Stellen Sie sicher, dass die Höhe ist match_parent und nicht wrap_content!

Benutzer-Avatar
Adeeb Karim

Spät, aber vielleicht hilfreich für jemanden, der {Suchelemente mit Animation} möchte

Verwenden Sie den folgenden Code in Ihrer Aktivität oder Fragment wo

yourAdapter.animateTo(filteredModelList);

Verwenden Sie den folgenden Code in Ihrer RecyclerAdapter-Klasse

public void animateTo(List<CommonModel> models) {
        applyAndAnimateRemovals(models);
        applyAndAnimateAdditions(models);
        applyAndAnimateMovedItems(models);
    }

    private void applyAndAnimateRemovals(List<CommonModel> newModels) {
        for (int i = items.size() - 1; i >= 0; i--) {
            final CommonModel model = items.get(i);
            if (!newModels.contains(model)) {
                removeItem(i);
            }
        }
    }

    private void applyAndAnimateAdditions(List<CommonModel> newModels) {
        for (int i = 0, count = newModels.size(); i < count; i++) {
            final CommonModel model = newModels.get(i);
            if (!items.contains(model)) {
                addItem(i, model);
            }
        }
    }

    private void applyAndAnimateMovedItems(List<CommonModel> newModels) {
        for (int toPosition = newModels.size() - 1; toPosition >= 0; toPosition--) {
            final CommonModel model = newModels.get(toPosition);
            final int fromPosition = items.indexOf(model);
            if (fromPosition >= 0 && fromPosition != toPosition) {
                moveItem(fromPosition, toPosition);
            }
        }
    }

    private CommonModel removeItem(int position) {
        final CommonModel model = items.remove(position);
        notifyItemRemoved(position);
        return model;
    }

    private void addItem(int position, CommonModel model) {
        items.add(position, model);
        notifyItemInserted(position);
    }

    private void moveItem(int fromPosition, int toPosition) {
        final CommonModel model = items.remove(fromPosition);
        items.add(toPosition, model);
        notifyItemMoved(fromPosition, toPosition);
    }

1205360cookie-checkKeine Animation beim Entfernen von Artikeln in RecyclerView

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy