web-dev-qa-db-fra.com

Animer la suppression d'un élément ListView

J'essaie d'animer la suppression d'un élément ListView en utilisant ceci:

    mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView, final View view, final int i, long l) {
            view.animate().setDuration(500).x(-view.getWidth()).alpha(0f);
            adapter.remove(tasks.get(i));
            adapter.notifyDataSetChanged();
        }
    });

Ça ne marche pas. J'ai essentiellement suivi les conseils de la 4ème réponse du haut de ce post:

Comment animer l'ajout ou la suppression de Android Lignes ListView

Cependant, il y a des trucs drôles de dessin en cours, ou de recyclage, ou quelque chose parce que pendant que l'animation se produit, l'élément en dessous de celui qui glisse hors de l'écran est également supprimé pour une raison quelconque. La réponse que le demandeur de questions a finalement marquée comme correcte est malheureusement un RTFM vers l'ensemble de la source d'Android. J'ai parcouru la liste et je ne trouve pas le menu déroulant des notifications dans JellyBean que j'essaie d'imiter.

TIA. John

31
John Wheeler

Je viens de trouver une belle solution: https://github.com/paraches/ListViewCellDeleteAnimation

Voici la vidéo: http://www.youtube.com/watch?v=bOl5MIti7n

Un grand merci à 'paraches';)

Modifier

À partir de Android version 22.0.0 le nouveau Android.support.v7.widget.RecyclerView est disponible en tant que successeur de ListView. Des animations standard d'ajout/suppression/mise à jour sont disponibles dès la sortie de l'emballage. Les animations des widgets sont également faciles à personnaliser ( quelques animations personnalisées ).

Je recommande fortement de passer de ListView à RecyclerView si vous avez besoin d'animations d'objets personnalisées.

34
Michal Vician

Idée: je démarre l'animation lorsque l'utilisateur sélectionne la ligne. Une fois l'animation terminée, je supprime la ligne de l'adaptateur. Le code suivant anime la ligne sélectionnée:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final ListView listView = (ListView) findViewById(R.id.listView1);
    final ArrayList<String> values = new ArrayList<String>();
    values.add("Android");
    values.add("iPhone");
    values.add("WindowsMobile");
    values.add("Blackberry");
    values.add("Windows7");

    final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
            Android.R.layout.simple_list_item_1, Android.R.id.text1, values);
    listView.setAdapter(adapter);

    final Animation animation = AnimationUtils.loadAnimation(this,
            R.anim.slide_out);
    animation.setAnimationListener(new AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            adapter.remove(adapter.getItem(selectedRow));
            adapter.notifyDataSetChanged();
        }
    });

    listView.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                int position, long id) {
            Toast.makeText(getApplicationContext(),
                    " " + values.get(position), Toast.LENGTH_LONG).show();
            view.startAnimation(animation);
            selectedRow = position;

        }

    });
}

fichier slide_out.xml:

<?xml version="1.0" encoding="utf-8"?>
 <set xmlns:Android="http://schemas.Android.com/apk/res/Android" >  
    <translate 
        Android:fromYDelta="0%" 
        Android:toYDelta="100%"  
        Android:duration="@Android:integer/config_mediumAnimTime"/>  
</set> 
38
Alexey

Comme le souligne Chet Haase dans DevBytes, https://www.youtube.com/watch?v=8MIfSxgsHIs , tout cela fonctionnera, mais n'oubliez pas d'ajouter des indicateurs transientState.

De son code:

// Here's where the problem starts - this animation will animate a View object.
                    // But that View may get recycled if it is animated out of the container,
                    // and the animation will continue to fade a view that now contains unrelated
                    // content.
                    ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, 0);
                    anim.setDuration(1000);
                    if (setTransientStateCB.isChecked()) {
                        // Here's the correct way to do this: if you tell a view that it has
                        // transientState, then ListView ill avoid recycling it until the
                        // transientState flag is reset.
                        // A different approach is to use ViewPropertyAnimator, which sets the
                        // transientState flag internally.
                        view.setHasTransientState(true);
                    }
                    anim.addListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            cheeseList.remove(item);
                            adapter.notifyDataSetChanged();
                            view.setAlpha(1);
                            if (setTransientStateCB.isChecked()) {
                                view.setHasTransientState(false);
                            }
                        }
                    });
                    anim.start();
4
AllDayAmazing

J'ai utilisé l'animation de diapositive de haut en bas pour actualiser le ListView. Voici le code que j'ai utilisé:

 adapter.notifyDataSetChanged();
 Animation animation = AnimationUtils.loadAnimation(
                    getApplication(), R.anim.slide_top_to_bottom);
 getListView().startAnimation(animation);
 getListView().setSelection(0);

et slide_top_to_bottom.xml (enregistrez-le dans res/anim dossier)

<?xml version="1.0" encoding="utf-8"?>

<set xmlns:Android="http://schemas.Android.com/apk/res/Android"   Android:interpolator="@Android:anim/accelerate_interpolator">
<translate Android:fromYDelta="-100%" Android:toXDelta="0" Android:duration="100" />
<alpha Android:fromAlpha="0.0" Android:toAlpha="1.0" Android:duration="50" />
</set>

EDIT: Essayez ceci:

mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, final View view, final int i, long l) {

    ValueAnimator fader = ObjectAnimator.ofFloat(view, "alpha", 1, 0);
    AnimatorSet animation = new AnimatorSet();
    animation.addListener(new AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {

        }
        @Override
        public void onAnimationRepeat(Animator animation) {
        }
        @Override
        public void onAnimationEnd(Animator animation) {

        }
        @Override
        public void onAnimationCancel(Animator animation) {
        }
    });
    ((AnimatorSet) animation).play(fader);
    animation.setDuration(500);
    animation.start();
    adapter.remove(tasks.get(i));
    adapter.notifyDataSetChanged();
}
});
1
Nishant