2014-11-28 18 views
42

Po raz pierwszy używam RecyclerView. Wszystko działa dobrze, z tym wyjątkiem, że nie ma animacji przy usuwaniu elementów, nawet jeśli animacja dodawania elementów działa dobrze.Brak animacji usuwania przedmiotu na RecyclerView

nie mam ustawić dowolny punkt animator zwyczaj, ale według documentation:

animacji na dodawanie i usuwanie elementów są domyślnie włączone w RecyclerView.

Animacje po usunięciu powinny działać.

Chciałbym mieć domyślną animację podczas usuwania, ale nie mogę tego uruchomić.

To jak ja skonfigurować RecyclerView:

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

To mój 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> 

Co robię źle, że powoduje domyślna animacja usuwania nie działa?

Odpowiedz

31

Rozwiązał problem.

Problem polegał na tym, że po wywołaniu mAdapter.remove(position), inna część mojego kodu wywoływała mAdapter.notifyDataSetChanged(), co do której zakładam, że zatrzymuje animację usuwania.

Podsumowując, jeśli zadzwonisz pod numer mAdapter.notifyDataSetChanged, gdy trwa animacja, animacja zostanie zatrzymana.

+9

i indeksy dostanie pomieszane jeśli nie. – milosmns

+0

, a następnie, jak naprawić? – MobileMon

+3

Rozwiązaniem tego problemu jest użycie metody viewHolder.getAdapterPosition() dla onClick zamiast pozycji przekazanej wewnątrz onBindViewHolder – MobileMon

-1

wpadłem na ten sam problem, i naprawiłem to przez wdrożenie własną RecyclerView, aw moim recyclerview, zrobiłem to:

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 
    } 

} 

Zasadniczo, jeśli dodać/usunąć element do/z recyclerview, ty można wywołać notifyItemInserted()/notifyItemRemoved() i notifyItemRangeChanged(), metoda ta wywoła onItemRangeRemoved()/onItemRangeInserted() w mDataObserver. Tak więc w tej metodzie można aktualizować widoczność pustego widoku i nie będzie on łamał animacji.

43

Właściwym sposobem, aby usunąć element z widoku recyklera jest usunięcie elementu z zestawu danych, a następnie mówi adapter, który element jest usuwany jak tak

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

dzięki, że to zadziałało dla mnie – commonSenseCode

3

udało mi się usunąć widok z animacja i zaktualizowane wskaźniki następująco:

w adaptera

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

Podczas wymiany poglądów, zadzwoń

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

Użyłem metody boolowskiej, aby zapewnić podwójne kliknięcia itp. nie powoduj awarii.

6

Zastosowanie notifyItemRemoved(position) zamiast notifyDataSetChanged() jak poniżej

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

ponieważ notifyDataSetChanged() prostu zawiadamia aktualizowane dane bez animacji.

5

Innym powodem nieprawidłowo działającego usunięcia animacji może być wysokość RecyclerViews. Sprawdź, czy wysokość to match_parent i NOT wrap_content!

+1

To kolejny powód. Animacja wstawiania działa z 'wrap_content', ale nie usuwa. Jakikolwiek sposób obejść to? –

2

po długim debugowania zdałem sobie sprawę, musiałem dodać setHasStableIds(true) do mojego zasilacza i wdrożenie

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

potem usunąć animacja zaczęła pracować

Powiązane problemy