Нет анимации при удалении элементов на RecyclerView
Я использую RecyclerView
в первый раз. Все работает отлично, за исключением того, что нет анимации при удалении элементов, даже если анимация при добавлении элементов работает просто отлично.
Я не задал ни одного настраиваемого элемента аниматора, но в соответствии с документацией:
Анимация для добавления и удаления элементов включена по умолчанию в RecyclerView
.
Таким образом, анимация при удалении должна работать.
Я хотел бы иметь анимацию по умолчанию при удалении, но не могу заставить это работать.
Вот как я настраиваю 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);
}
Это мой адаптер:
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>
Что я делаю неправильно, что приводит к тому, что анимация удаления по умолчанию не работает?
Ответы
Ответ 1
Правильный способ удаления элемента из представления recycler состоит в том, чтобы удалить элемент из набора данных, а затем сообщить адаптеру, что элемент удален таким образом
myDataset.remove(position); // myDataset is List<MyObject>
mAdapter.notifyItemRemoved(position);
Ответ 2
Решил.
Проблема заключалась в том, что после вызова mAdapter.remove(position)
другая часть моего кода вызывала mAdapter.notifyDataSetChanged()
, который, как я полагаю, останавливает анимацию удаления.
Подводя итог, если вы вызываете mAdapter.notifyDataSetChanged
, пока анимация продолжается, анимация останавливается.
Ответ 3
Используйте notifyItemRemoved(position)
вместо notifyDataSetChanged()
, как показано ниже
myDataset.remove(position);
notifyItemRemoved(position);
потому что notifyDataSetChanged()
просто уведомляет обновленные данные без каких-либо анимаций.
Ответ 4
Другой причиной неэффективной обработки удаленной анимации может быть высота RecyclerViews
. Убедитесь, что высота match_parent
и NOT wrap_content
!
Ответ 5
Мне удалось удалить представление с анимацией и обновленными индексами следующим образом:
Внутри адаптера
public boolean removeItem(int position) {
if (data.size() >= position + 1) {
data.remove(position);
return true;
}
return false;
}
Во время удаления представлений вызовите
if (adapter.removeItem(position)) {
adapter.notifyItemRemoved(position);
adapter.notifyItemRangeChanged(position, adapter.getItemCount());
}
Я использовал логический метод для обеспечения двойного щелчка и т.д. не вызывают сбоев.
Ответ 6
после долгой отладки я понял, что мне пришлось добавить setHasStableIds(true)
к моему адаптеру и реализовать
@Override
public long getItemId(int position) {
return position;
}
после этого удаленная анимация начала работать
Ответ 7
Я столкнулся с одной и той же проблемой, и я исправил это, реализовав мой собственный RecyclerView, и в моем recyclerview я сделал это:
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 visibility
}
}
В принципе, когда вы добавляете/удаляете элемент в/из recyclerview, вы можете вызывать notifyItemInserted()/notifyItemRemoved() и notifyItemRangeChanged(), этот метод будет вызывать onItemRangeRemoved()
/onItemRangeInserted()
в mDataObserver
. Таким образом, в этом методе вы можете обновлять видимость видимого вида и не прерывать анимацию.