首页 文章

在RecyclerView上删除项目时没有动画

提问于
浏览
52

我是第一次使用 RecyclerView . 一切都工作正常,除了项目删除没有动画,即使项目添加动画工作正常 .

我没有设置任何自定义项目动画师,但根据documentation

在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>

我做错了什么导致默认删除动画不起作用?

8 回答

  • 5

    从回收站视图中删除项目的正确方法是从数据集中删除该项目,然后告诉适配器该项目已被删除

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

    解决了它 .

    问题是,在调用 mAdapter.remove(position) 之后,我的代码的另一部分是调用 mAdapter.notifyDataSetChanged() ,我假设停止删除动画 .

    总而言之,如果在动画正在进行时调用 mAdapter.notifyDataSetChanged ,则动画将停止 .

  • 3

    如下所示,使用 notifyItemRemoved(position) 而不是 notifyDataSetChanged()

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

    因为 notifyDataSetChanged() 只是在没有任何动画的情况下通知更新的数据 .

  • -1

    我能够使用动画和更新的索引删除视图,如下所示:

    在适配器内,

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

    我使用了一个布尔方法来确保双击等 . 不要导致崩溃 .

  • 10

    不正确工作删除动画的另一个原因可能是 RecyclerViews 高度 . 确认高度是 match_parent 而不是 wrap_content

  • 50

    经过长时间的调试后,我意识到我必须将 setHasStableIds(true) 添加到我的适配器并实现

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

    之后删除动画开始工作

  • 5

    迟到但可能对想要{搜索带动画的项目}的人有所帮助

    使用下面的代码在您的活动或片段中

    yourAdapter.animateTo(filteredModelList);
    

    在RecyclerAdapter类中使用以下代码

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

    我遇到了同样的问题,我通过实施自己的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's visibility
        }
    
    }
    

    基本上,当您在recyclerview中添加/删除项目时,可以调用notifyItemInserted()/ notifyItemRemoved()和notifyItemRangeChanged(),这些方法将在 mDataObserver 中调用 onItemRangeRemoved() / onItemRangeInserted() . 因此,在这些方法中,您可以更新空视图的可见性,并且不会破坏动画 .

相关问题