Comment animer L'ajout ou la suppression de lignes ListView Android

dans iOS, il y a une facilité très facile et puissante pour animer l'ajout et la suppression des lignes de vue utilisables, voici un clip d'une vidéo youtube montrant l'animation par défaut. Notez comment les lignes environnantes s'effondrent sur la ligne supprimée. Cette animation aide les utilisateurs à garder une trace de ce qui a changé dans une liste et où dans la liste ils étaient en train de regarder quand les données ont changé.

depuis que je me suis développé sur Android je n'ai trouvé aucun équivalent possibilité d'animer des lignes individuelles dans une TableView . En appelant notifyDataSetChanged() sur mon adaptateur, ListView met immédiatement à jour son contenu avec de nouvelles informations. J'aimerais vous montrer une simple animation d'une nouvelle ligne, poussant dans coulissantes ou lorsque les données changent, mais je ne trouve pas toutes documentées façon de le faire. Il ressemble à LayoutAnimationController pourrait tenir une clé pour obtenir ce à travailler, mais quand je mets un LayoutAnimationController sur mon ListView (similaire à LayoutAnimation2 D'ApiDemo ) et supprimer des éléments de mon adaptateur après l'affichage de la liste, les éléments disparaissent immédiatement au lieu de s'animer.

j'ai également essayé des choses comme les suivantes pour animer un élément lorsqu'il est supprimé:

@Override
protected void onListItemClick(ListView l, View v, final int position, long id) {
    Animation animation = new ScaleAnimation(1, 1, 1, 0);
    animation.setDuration(100);
    getListView().getChildAt(position).startAnimation(animation);
    l.postDelayed(new Runnable() {
        public void run() {
            mStringList.remove(position);
            mAdapter.notifyDataSetChanged();
        }
    }, 100);
}

cependant, les rangées entourant la rangée animée ne bougent pas la position jusqu'à ce qu'ils sautent à leur nouveau positions lorsque notifyDataSetChanged() est appelé. Il semble que ListView ne mette pas à jour sa mise en page une fois que ses éléments ont été placés.

en écrivant ma propre implémentation/fork de ListView m'a traversé l'esprit, cela ressemble à quelque chose qui ne devrait pas être si difficile.

Merci!

206
demandé sur Alex Pretzlav 2010-10-14 01:29:01

14 réponses

Animation anim = AnimationUtils.loadAnimation(
                     GoTransitApp.this, android.R.anim.slide_out_right
                 );
anim.setDuration(500);
listView.getChildAt(index).startAnimation(anim );

new Handler().postDelayed(new Runnable() {

    public void run() {

        FavouritesManager.getInstance().remove(
            FavouritesManager.getInstance().getTripManagerAtIndex(index)
        );
        populateList();
        adapter.notifyDataSetChanged();

    }

}, anim.getDuration());

pour l'animation de haut en bas:

<set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate android:fromYDelta="20%p" android:toYDelta="-20"
            android:duration="@android:integer/config_mediumAnimTime"/>
        <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
            android:duration="@android:integer/config_mediumAnimTime" />
</set>
122
répondu OAK 2012-03-22 08:58:15

consultez la solution Google. Voici une méthode de suppression seulement.

ListViewRemovalAnimation code du projet et vidéo démonstration

il a besoin D'Android 4.1+ (API 16). Mais nous avons 2014 à l'extérieur.

9
répondu dimetil 2014-07-31 17:36:29

depuis ListViews sont fortement optimisés je pense que ce n'est pas possible d'accieve. Avez-vous essayé de créer votre "ListView" par code (c'est-à-dire en gonflant vos lignes à partir du xml et en les ajoutant à un LinearLayout ) et de les animer?

2
répondu whlk 2010-10-16 23:31:55

avez-vous envisagé d'animer un balayage à droite? Vous pourriez faire quelque chose comme dessiner une barre blanche de plus en plus grande à travers le haut de l'élément de liste, puis le supprimer de la liste. Les autres cellules se branleraient encore, mais c'est mieux que rien.

2
répondu Sam Dufel 2010-10-17 22:03:26

appel listView.scheduleLayoutAnimation(); avant de changer la liste

2
répondu karabara 2012-12-13 06:07:39

j'ai piraté ensemble une autre façon de le faire sans avoir à manipuler la vue Liste. Malheureusement, les Animations Android régulières semblent manipuler le contenu de la rangée, mais sont inefficaces pour rétrécir réellement la vue. Ainsi, d'abord considérer ce handler:

private Handler handler = new Handler() {
@Override
public void handleMessage(Message message) {
    Bundle bundle = message.getData();

    View view = listView.getChildAt(bundle.getInt("viewPosition") - 
        listView.getFirstVisiblePosition());

    int heightToSet;
    if(!bundle.containsKey("viewHeight")) {
        Rect rect = new Rect();
        view.getDrawingRect(rect);
        heightToSet = rect.height() - 1;
    } else {
        heightToSet = bundle.getInt("viewHeight");
    }

    setViewHeight(view, heightToSet);

    if(heightToSet == 1)
        return;

    Message nextMessage = obtainMessage();
    bundle.putInt("viewHeight", (heightToSet - 5 > 0) ? heightToSet - 5 : 1);
    nextMessage.setData(bundle);
    sendMessage(nextMessage);
}

Ajoutez cette collection à votre liste adaptateur:

private Collection<Integer> disabledViews = new ArrayList<Integer>();

et ajouter

public boolean isEnabled(int position) {
   return !disabledViews.contains(position);
}

ensuite, où que vous vouliez cacher une rangée, ajouter ceci:

Message message = handler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putInt("viewPosition", listView.getPositionForView(view));
message.setData(bundle);
handler.sendMessage(message);    
disabledViews.add(listView.getPositionForView(view));

C'est ça! Vous pouvez modifier la vitesse de l'animation en modifiant le nombre de pixels qu'il prenne de la hauteur à la fois. Pas de réel sophistiqué, mais il fonctionne!

2
répondu jkschneider 2014-12-16 21:41:56

après avoir inséré une nouvelle ligne dans ListView, je fais simplement défiler ListView vers une nouvelle position.

ListView.smoothScrollToPosition(position);
2
répondu Rafael 2015-01-21 11:01:46

Je ne l'ai pas essayé mais il ressemble animateLayoutChanges devrait faire ce que vous recherchez. Je le vois dans la classe ImageSwitcher, je suppose que c'est aussi dans la classe ViewSwitcher?

1
répondu Genia S. 2011-06-19 15:38:33

comme Android est open source, vous n'avez pas besoin de réimplémenter les optimisations de ListView. Vous pouvez récupérer le code de ListView et essayer de trouver un moyen de pirater l'animation, vous pouvez aussi ouvrir une requête de fonctionnalité dans android bug tracker (et si vous avez décidé de l'implémenter, n'oubliez pas de contribuer un patch ).

POUR INFORMATION, Le code source de ListView est ici .

1
répondu Lie Ryan 2011-07-28 21:58:35

voici le code source pour vous permettre de supprimer les lignes et de les réorganiser.

un fichier de démonstration APK est également disponible. La suppression de lignes se fait plus dans le sens de L'application Gmail de Google qui révèle une vue en bas après avoir fait glisser une vue en haut. La vue du bas peut avoir un bouton Annuler ou ce que vous voulez.

1
répondu AndroidDev 2015-08-21 10:18:18

comme j'avais expliqué mon approche dans mon site j'ai partagé le lien.De toute façon l'idée est de créer des images bitmap par getdrawingcache .avoir deux bitmap et animer le bitmap inférieur pour créer l'effet mobile

s'il vous plaît voir le code suivant:

listView.setOnItemClickListener(new AdapterView.OnItemClickListener()
    {
        public void onItemClick(AdapterView<?> parent, View rowView, int positon, long id)
        {
            listView.setDrawingCacheEnabled(true);
            //listView.buildDrawingCache(true);
            bitmap = listView.getDrawingCache();
            myBitmap1 = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), rowView.getBottom());
            myBitmap2 = Bitmap.createBitmap(bitmap, 0, rowView.getBottom(), bitmap.getWidth(), bitmap.getHeight() - myBitmap1.getHeight());
            listView.setDrawingCacheEnabled(false);
            imgView1.setBackgroundDrawable(new BitmapDrawable(getResources(), myBitmap1));
            imgView2.setBackgroundDrawable(new BitmapDrawable(getResources(), myBitmap2));
            imgView1.setVisibility(View.VISIBLE);
            imgView2.setVisibility(View.VISIBLE);
            RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            lp.setMargins(0, rowView.getBottom(), 0, 0);
            imgView2.setLayoutParams(lp);
            TranslateAnimation transanim = new TranslateAnimation(0, 0, 0, -rowView.getHeight());
            transanim.setDuration(400);
            transanim.setAnimationListener(new Animation.AnimationListener()
            {
                public void onAnimationStart(Animation animation)
                {
                }

                public void onAnimationRepeat(Animation animation)
                {
                }

                public void onAnimationEnd(Animation animation)
                {
                    imgView1.setVisibility(View.GONE);
                    imgView2.setVisibility(View.GONE);
                }
            });
            array.remove(positon);
            adapter.notifyDataSetChanged();
            imgView2.startAnimation(transanim);
        }
    });

Pour comprendre avec des images de cette

Merci.

1
répondu Ram 2015-08-21 10:28:08

j'ai fait quelque chose de similaire. Une approche consiste à interpoler sur le temps d'animation la hauteur de la vue dans le temps à l'intérieur des lignes onMeasure tout en émettant requestLayout() pour le listView. Oui, il est peut-être préférable de le faire directement à l'intérieur du code listView, mais c'était une solution rapide (qui avait l'air bien!)

0
répondu Dori 2012-05-04 13:09:07

Juste partager une autre approche:

premier paramétrage de la vue Liste android: animateLayoutChanges à true :

<ListView
        android:id="@+id/items_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:animateLayoutChanges="true"/>

puis j'utilise un handler pour ajouter des éléments et mettre à jour le listview avec retard:

Handler mHandler = new Handler();
    //delay in milliseconds
    private int mInitialDelay = 1000;
    private final int DELAY_OFFSET = 1000;


public void addItem(final Integer item) {
    mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    mDataSet.add(item);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mAdapter.notifyDataSetChanged();
                        }
                    });
                }
            }).start();

        }
    }, mInitialDelay);
    mInitialDelay += DELAY_OFFSET;
}
0
répondu Mina Samy 2016-08-10 16:01:02