J'utilise RecyclerView
pour la première fois. Tout fonctionne bien sauf qu'il n'y a pas d'animation sur la suppression d'éléments, même si l'animation sur l'ajout d'éléments fonctionne parfaitement.
Je n'ai pas défini d'animateur d'élément personnalisé, mais selon la documentation :
Les animations pour l'ajout et la suppression d'éléments sont activées par défaut dans
RecyclerView
.
Donc, les animations sur la suppression devraient fonctionner.
J'aimerais que l'animation par défaut soit supprimée, mais je ne parviens pas à la faire fonctionner.
Voici comment j'ai configuré le 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);
}
Ceci est mon adaptateur:
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>
Qu'est-ce que je fais de mal qui fait que l'animation de suppression par défaut ne fonctionne pas?
La méthode appropriée pour supprimer un élément de la vue du recycleur consiste à supprimer l'élément du jeu de données, puis à indiquer à l'adaptateur que l'élément est supprimé,
myDataset.remove(position); // myDataset is List<MyObject>
mAdapter.notifyItemRemoved(position);
Résolu.
Le problème était que, après avoir appelé mAdapter.remove(position)
, une autre partie de mon code appelait mAdapter.notifyDataSetChanged()
, ce qui, je suppose, arrête l'animation de suppression.
En résumé, si vous appelez mAdapter.notifyDataSetChanged
pendant qu’une animation est en cours, celle-ci s’arrête.
Utilisez notifyItemRemoved(position)
au lieu de notifyDataSetChanged()
comme ci-dessous
myDataset.remove(position);
notifyItemRemoved(position);
parce que notifyDataSetChanged()
notifie simplement les données mises à jour sans aucune animation.
Une autre raison pour laquelle une animation de suppression ne fonctionne pas correctement peut être la hauteur RecyclerViews
Vérifiez que la hauteur est match_parent
et NOT wrap_content
!
J'ai pu supprimer la vue avec l'animation et les index mis à jour comme suit:
Dans l'adaptateur,
public boolean removeItem(int position) {
if (data.size() >= position + 1) {
data.remove(position);
return true;
}
return false;
}
Tout en supprimant les vues, appelez
if (adapter.removeItem(position)) {
adapter.notifyItemRemoved(position);
adapter.notifyItemRangeChanged(position, adapter.getItemCount());
}
J'ai utilisé une méthode booléenne pour m'assurer que les doubles clics, etc. ne provoque pas de crash.
après un long débogage, j'ai réalisé que je devais ajouter setHasStableIds(true)
à mon adaptateur et le mettre en œuvre.
@Override
public long getItemId(int position) {
return position;
}
après que supprimer l'animation a commencé à travailler
En retard mais pourrait être utile à quelqu'un qui veut {rechercher des éléments avec animation}
Utilisez le code ci-dessous dans votre activité ou fragment où
yourAdapter.animateTo(filteredModelList);
Utilisez le code ci-dessous dans votre classe 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);
}