2014-11-28 4 views
42

Ich verwende RecyclerView zum ersten Mal. Alles funktioniert gut, außer dass beim Entfernen von Objekten keine Animation vorhanden ist, obwohl die Animation für die Elementhinzufügung problemlos funktioniert.Keine Animation zum Entfernen von Artikeln auf RecyclerView

ich gesetzt habe keinen benutzerdefiniertes Element Animator, sondern nach den documentation:

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

So sollten die Animationen zum Entfernen funktionieren.

Ich möchte die Standard-Animation auf Entfernung haben, aber das kann nicht funktionieren. Diese

ist, wie ich Setup die RecyclerView:

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:

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 ist

<?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 die bewirkt, dass die Standard-Entfernungsanimation funktioniert nicht?

Antwort

31

Gelöst es.

Das Problem war, dass, nach dem Aufruf mAdapter.remove(position), ein anderer Teil meines Codes mAdapter.notifyDataSetChanged() anrief, von dem ich annehme, stoppt die Abbauanimation.

Zusammenfassend, wenn Sie mAdapter.notifyDataSetChanged aufrufen, während eine Animation läuft, wird die Animation gestoppt.

+9

und Indizes zu arbeiten, wenn Sie nicht bekommen, vermasselt. – milosmns

+0

dann wie zu beheben? – MobileMon

+3

Die Lösung, um dieses Problem zu beheben, ist die Verwendung von viewHolder.getAdapterPosition() für onClick anstelle der Position innerhalb von onBindViewHolder übergeben – MobileMon

-1

lief ich in gleiche Problem, und ich festgelegt dies durch meine eigenen RecyclerView Implementierung und in meinem recyclerview, ich habe dies:

public class MyRecyclerView extends RecyclerView { 
    private View mEmptyView; 
    private AdapterDataObserver mDataObserver = new AdapterDataObserver() { 
     public void onChanged() { 
      super.onChanged(); 
      updateEmptyView(); 
     } 

     public void onItemRangeRemoved(int positionStart, int itemCount) { 
      super.onItemRangeRemoved(positionStart, itemCount); 
      updateEmptyView(); 
     } 

     public void onItemRangeInserted(int positionStart, int itemCount) { 
      super.onItemRangeInserted(positionStart, itemCount); 
      updateEmptyView(); 
     } 
    }; 

    // private void setAdapter() {} 

    private void updateEmptyView() { 
     // update empty view's visibility 
    } 

} 

Grundsätzlich, wenn Sie Artikel in/aus recyclerview hinzufügen/entfernen, Sie kann notifyItemInserted()/notifyItemRemoved() und notifyItemRangeChanged() aufrufen, diese Methoden rufen onItemRangeRemoved()/onItemRangeInserted() in mDataObserver auf. In dieser Methode können Sie die Sichtbarkeit der leeren Ansicht aktualisieren und Animationen nicht unterbrechen.

43

Der richtige Weg, ein Element aus Recycler Ansicht zu entfernen, ist das Element aus Datensatz zu entfernen und dann den Adapter zu sagen, dass das Element wie so

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

danke Mann das für mich funktioniert – commonSenseCode

3

konnte ich entfernt, um die Ansicht mit der entfernen Animation und aktualisierte Indizes wie folgt:

innerhalb des Adapters,

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

Während die Ansichten zu entfernen, rufen Sie

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.

6

Verwenden notifyItemRemoved(position) statt notifyDataSetChanged() wie unter

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

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

5

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

+1

Das ist ein weiterer Grund. Die Insert-Animation arbeitet mit 'wrap_content', aber nicht mit dem Entfernen. Irgendeine Möglichkeit, dies zu umgehen? –

2

nach langer Fehlersuche wurde mir klar, ich setHasStableIds(true) meinen Adapter hinzuzufügen hatte und

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

zu implementieren danach Animation entfernen begann