Jak animować dodawanie lub usuwanie wierszy systemu Android ListView

W systemie iOS istnieje bardzo łatwy i potężny mechanizm do animowania dodawania i usuwania wierszy UITableView, Oto klip z filmu youtube pokazujący domyślną animację. Zauważ, jak otaczające wiersze zapadają się na usunięty wiersz. Ta animacja pomaga użytkownikom śledzić, co zmieniło się na liście i gdzie na liście przeglądali, gdy DANE się zmieniły.

Ponieważ rozwijałem się na Androidzie, nie znalazłem odpowiedniego narzędzia do animowania poszczególnych wierszy w a TableView . Calling notifyDataSetChanged() na mój Adapter powoduje, że ListView natychmiast aktualizuje swoją zawartość o nowe informacje. Chciałbym pokazać prostą animację nowego wiersza wciskającego się lub wysuwającego po zmianie danych, ale nie mogę znaleźć żadnego udokumentowanego sposobu, aby to zrobić. Wygląda na to, że LayoutAnimationController może posiadać klucz do uruchomienia tego, ale kiedy ustawiam LayoutAnimationController w moim ListView (podobnie do Apidemo LayoutAnimation2 ) i usuwanie elementów z mojego adaptera po wyświetleniu listy elementy znikają natychmiast,zamiast być animowane.

Próbowałem również wykonać następujące czynności, aby animować pojedynczy element po jego usunięciu:

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

Jednak wiersze otaczające animowany wiersz nie przesuwają się, dopóki nie przeskoczą do nowych pozycji po wywołaniu notifyDataSetChanged(). Wygląda na to, że ListView nie aktualizuje układu Po umieszczeniu jego elementów.

Podczas pisania własnego implementacja / widelec ListView przeszło mi przez myśl, wydaje się to czymś, co nie powinno być tak trudne.

Dzięki!
Author: Alex Pretzlav, 2010-10-14

14 answers

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

Do wykorzystania animacji top-to-down:

<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
Author: OAK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-22 08:58:15
 14
Author: Eric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-27 20:32:30

Spójrz na rozwiązanie Google. Tutaj jest tylko metoda usuwania.

ListViewRemovalAnimation Kod projektu i Wideo demonstracja

Potrzebuje Androida 4.1+ (API 16). Ale mamy 2014 Na Zewnątrz.

 9
Author: dimetil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-31 17:36:29

Ponieważ {[0] } są wysoce zoptymalizowane, myślę, że nie jest to możliwe do osiągnięcia. Czy próbowałeś utworzyć swój "ListView" za pomocą kodu (tj. pompując wiersze z xml i dołączając je do LinearLayout) i animować je?

 2
Author: whlk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-16 23:31:55

Czy rozważałeś animację zamiatania w prawo? Możesz zrobić coś takiego, jak narysowanie stopniowo większego białego paska u góry elementu listy, a następnie usunięcie go z listy. Inne komórki nadal by się na to rzuciły, ale to lepsze niż nic.

 2
Author: Sam Dufel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-17 22:03:26

Call listView.scheduleLayoutAnimation(); przed zmianą listy

 2
Author: karabara,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-13 06:07:39

Zhakowałem inny sposób, aby to zrobić bez konieczności manipulowania widokiem listy. Niestety, zwykłe animacje Androida wydają się manipulować zawartością wiersza, ale są nieskuteczne w faktycznym zmniejszaniu widoku. Więc najpierw rozważ ten 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);
}

Dodaj tę kolekcję do swojej listy:

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

I dodać

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

Następnie, gdziekolwiek chcesz ukryć wiersz, dodaj to:

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));
To jest to! Szybkość animacji można zmienić poprzez zmiana liczby pikseli, które zmniejszają wysokość na raz. Niezbyt wyrafinowane, ale działa!
 2
Author: jkschneider,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-16 21:41:56

Po wstawieniu nowego wiersza do ListView, po prostu przewijam ListView do nowej pozycji.

ListView.smoothScrollToPosition(position);
 2
Author: Rafael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-21 11:01:46

Nie próbowałem, ale wygląda na to, że animateLayoutChanges powinien robić to, czego szukasz. Widzę to w klasie ImageSwitcher, zakładam, że jest też w klasie ViewSwitcher?

 1
Author: Genia S.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-19 15:38:33

Ponieważ Android jest open source, nie musisz reimplementować optymalizacji ListView. Możesz pobrać kod ListView i spróbować znaleźć sposób na włamanie w animacji, Możesz również otworzyć żądanie funkcji w Android bug tracker (i jeśli zdecydowałeś się go wdrożyć, nie zapomnij przyczynić się do poprawki ).

Dla twojej wiadomości, kod źródłowy ListView to tutaj .

 1
Author: Lie Ryan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-28 21:58:35

Oto kod źródłowy , który pozwoli Ci usunąć wiersze i zmienić ich kolejność.

Plik demo APK jest również dostępny. Usuwanie wierszy odbywa się bardziej zgodnie z linią aplikacji Gmail Google, która ujawnia widok dolny po przesunięciu widoku z góry. Widok dolny może mieć Przycisk Cofnij lub cokolwiek chcesz.

 1
Author: AndroidDev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-21 10:18:18

Jak wyjaśniłem moje podejście na mojej stronie, udostępniłem link.W każdym razie pomysł jest tworzenie bitmapy przez getdrawingcache .użyj dwóch bitmap i Animuj niższą bitmapę, aby utworzyć efekt ruchu

Zobacz następujący kod:

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

Aby zrozumieć obrazy Zobacz to

Dzięki.
 1
Author: Ram,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-21 10:28:08

Zrobiłem coś podobnego. Jedną z metod jest interpolacja w czasie animacji wysokości widoku w czasie wewnątrz wierszy onMeasure podczas wydawania requestLayout() dla listView. Tak może być lepiej zrobić bezpośrednio w kodzie listView, ale było to szybkie rozwiązanie (które wyglądało dobrze!)

 0
Author: Dori,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-04 13:09:07

Po prostu dzielę się innym podejściem:

Najpierw ustaw widok listy android: animateLayoutChanges na true :

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

Następnie używam handler aby dodawać elementy i aktualizować listview z opóźnieniem:

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
Author: Mina Samy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-10 16:01:02