Cara Menghidupkan Penambahan atau Penghapusan Baris Android ListView

212

Di iOS, ada fasilitas yang sangat mudah dan kuat untuk menganimasikan penambahan dan penghapusan baris UITableView, inilah klip dari video youtube yang menunjukkan animasi default. Perhatikan bagaimana baris di sekitarnya runtuh ke baris yang dihapus. Animasi ini membantu pengguna melacak apa yang berubah dalam daftar dan di mana dalam daftar yang mereka lihat ketika data berubah.

Karena saya telah mengembangkan di Android, saya tidak menemukan fasilitas yang setara untuk menghidupkan setiap baris di TableView . Memanggil notifyDataSetChanged()Adaptor saya menyebabkan ListView segera memperbarui kontennya dengan informasi baru. Saya ingin menunjukkan animasi sederhana dari baris baru yang mendorong atau meluncur ketika data berubah, tetapi saya tidak dapat menemukan cara yang terdokumentasi untuk melakukan ini. Sepertinya LayoutAnimationController mungkin memegang kunci untuk membuat ini berfungsi, tetapi ketika saya mengatur LayoutAnimationController pada ListView saya (mirip dengan LayoutAnimation2 ApiDemo ) dan menghapus elemen dari adaptor saya setelah daftar ditampilkan, elemen-elemen menghilang segera alih-alih menjadi animasi keluar .

Saya juga sudah mencoba hal-hal seperti berikut ini untuk menghidupkan barang individual ketika dihapus:

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

Namun, baris yang mengelilingi baris animasi tidak bergerak posisi sampai mereka melompat ke posisi baru ketika notifyDataSetChanged()dipanggil. Tampaknya ListView tidak memperbarui tata letaknya setelah elemen-elemennya ditempatkan.

Saat menulis implementasi saya sendiri / garpu ListView telah terlintas di benak saya, ini sepertinya sesuatu yang seharusnya tidak terlalu sulit.

Terima kasih!

Alex Pretzlav
sumber
apakah ada yang menemukan jawaban untuk ini? tolong bagikan
AndroidGecko
@Alex: sudahkah Anda melakukan animasi seperti itu video youtube (seperti iphone), Jika Anda memiliki demo atau tautan untuk android maka tolong beri saya, saya telah mencoba menggunakan animateLayoutChanges dalam file xml, tetapi tidak persis seperti iphone
Jayesh
@ Jayesh, sayangnya saya tidak lagi bekerja pada pengembangan Android. Saya belum menguji salah satu jawaban untuk pertanyaan ini yang ditulis setelah sekitar 2012.
Alex Pretzlav

Jawaban:

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

untuk penggunaan animasi 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>
EK
sumber
70
Lebih baik menggunakan anim.setAnimationListener(new AnimationListener() { ... })daripada menggunakan Handler
Oleg Vaskevich
1
apa populateList()untuk?
Vasily Sochinsky
5
@ MrAppleBR karena beberapa alasan. Pertama, Anda tidak membuat yang tidak dibutuhkan Handler. Kedua, itu membuat kode lebih kompleks dengan sudah menggunakan panggilan balik bawaan untuk saat animasi selesai. Ketiga, Anda tidak tahu bagaimana implementasi Handlerdan Animationakan bekerja pada setiap platform; mungkin saja runnable tertunda Anda terjadi sebelum animasi selesai.
Oleg Vaskevich
7
"Namun, baris yang mengelilingi baris animasi tidak bergerak posisi sampai mereka melompat ke posisi baru mereka ketika notifyDataSetChanged () dipanggil." masalah ini masih ada dalam solusi Anda.
Boris Rusev
5
Apa itu metode kelas dan populateList FavouritesManager ??
Jayesh
14

Yang RecyclerViewmengurus menambahkan, menghapus, dan memesan ulang animasi!

RecyclerView sedang beraksi

Ini proyek AndroidStudio sederhana fitur RecyclerView. lihat komit :

  1. komit dari aplikasi Android Hello World klasik
  2. komit, menambahkan RecyclerView ke proyek (konten tidak dinamis)
  3. komit, menambahkan fungsionalitas untuk memodifikasi konten RecyclerView saat runtime (tetapi tidak ada animasi)
  4. dan akhirnya ... komit untuk menambahkan animasi ke RecyclerView
Eric
sumber
1
Saya pikir ini adalah cara sederhana ketika Anda membutuhkan animasi sederhana, tetapi Anda juga dapat mengubahsuaikan animasi menggunakan metode RecyclerView.setItemAnimator ().
qatz
2
Langkah terakhir adalah tautan yang hilang yang saya miliki. Id stabil. Terima kasih!
Amir Uval
Ini adalah contoh proyek luar biasa yang menunjukkan API dengan baik.
Mr-IDE
9

Lihatlah solusi Google. Berikut adalah metode penghapusan saja.

Kode proyek ListViewRemovalAnimation dan demonstrasi Video

Perlu Android 4.1+ (API 16). Tapi kami punya 2014 di luar.

dimetil
sumber
2

Karena ListViewssangat dioptimalkan saya pikir ini tidak mungkin untuk diterima. Sudahkah Anda mencoba membuat "ListView" Anda dengan kode (yaitu dengan menggembungkan baris Anda dari xml dan menambahkannya ke a LinearLayout) dan menghidupkannya?

whlk
sumber
6
Tidak masuk akal untuk mengimplementasikan kembali tampilan daftar hanya untuk menambahkan animasi.
Macarse
Saya tentu saja bisa menggunakan LinearLayout, namun dengan LinearLayoutkinerja dataset yang sangat besar akan menjadi sangat buruk. ListViewmemiliki banyak optimisasi pintar seputar daur ulang tampilan yang memungkinkannya menangani set data besar (UITableView iOS memiliki optimisasi yang sama). Menulis tampilan saya sendiri pendaur ulang berada di bawah kategori
penerapan
Saya tahu itu tidak masuk akal - tetapi jika Anda bekerja dengan hanya beberapa baris manfaat dari memiliki animasi masuk / keluar yang bagus bisa patut dicoba.
whlk
2

Sudahkah Anda mempertimbangkan menggerakkan sapuan ke kanan? Anda dapat melakukan sesuatu seperti menggambar bilah putih yang semakin besar di bagian atas item daftar, lalu mengeluarkannya dari daftar. Sel-sel lain masih akan menyentak ke tempatnya, tetapi lebih baik daripada tidak sama sekali.

Sam Dufel
sumber
2

panggil listView.scheduleLayoutAnimation (); sebelum mengubah daftar

karabara
sumber
2

Saya meretas bersama cara lain untuk melakukannya tanpa harus memanipulasi tampilan daftar. Sayangnya, Animasi Android biasa tampaknya memanipulasi isi baris, tetapi tidak efektif untuk benar-benar mengecilkan tampilan. Jadi, pertama-tama pertimbangkan penangan ini:

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

Tambahkan koleksi ini ke adaptor Daftar Anda:

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

dan tambahkan

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

Selanjutnya, di mana pun Anda ingin menyembunyikan baris, tambahkan ini:

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

Itu dia! Anda dapat mengubah kecepatan animasi dengan mengubah jumlah piksel yang menyusut tingginya sekaligus. Tidak benar-benar canggih, tetapi berhasil!

jkschneider
sumber
2

Setelah memasukkan baris baru ke ListView, saya hanya menggulir ListView ke posisi baru.

ListView.smoothScrollToPosition(position);
Rafael
sumber
1

Saya belum mencobanya tetapi sepertinya animateLayoutChanges harus melakukan apa yang Anda cari. Saya melihatnya di kelas ImageSwitcher, saya menganggap itu di kelas ViewSwitcher juga?

Yevgeny Simkin
sumber
Hai terima kasih, saya akan memeriksanya. Sayangnya sepertinya animateLayoutChanges baru pada API Level 11 alias Honeycomb alias tidak dapat menggunakan ini di ponsel apa pun :(
Alex Pretzlav
1

Karena Android adalah open source, Anda sebenarnya tidak perlu mengimplementasikan kembali optimasi ListView. Anda dapat mengambil kode ListView dan mencoba menemukan cara untuk meretas dalam animasi, Anda juga dapat membuka permintaan fitur di pelacak bug android (dan jika Anda memutuskan untuk menerapkannya, jangan lupa untuk berkontribusi tambalan ).

FYI, kode sumber ListView ada di sini .

Lie Ryan
sumber
1
Ini bukan cara perubahan semacam itu harus diterapkan. Sebelum apa pun, Anda harus memiliki gedung proyek AOSP - yang merupakan pendekatan yang cukup berat untuk menambahkan animasi ke tampilan daftar. Silakan lihat implementasi di berbagai pustaka sumber terbuka.
OrhanC1
1

Berikut kode sumber untuk memungkinkan Anda menghapus baris dan menyusun ulangnya.

File demo APK juga tersedia. Menghapus baris dilakukan lebih banyak di sepanjang baris aplikasi Gmail Google yang mengungkapkan tampilan bawah setelah menggesek tampilan atas. Tampilan bawah dapat memiliki tombol Undo atau apa pun yang Anda inginkan.

AndroidDev
sumber
1

Seperti yang saya telah menjelaskan pendekatan saya di situs saya, saya membagikan tautannya. Bagaimanapun idenya adalah membuat bitmap dengan getdrawingcache. Memiliki dua bitmap dan menghidupkan bitmap yang lebih rendah untuk menciptakan efek bergerak

Silakan lihat kode berikut:

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

Untuk memahami dengan gambar lihat ini

Terima kasih.

Ram
sumber
0

Saya telah melakukan sesuatu yang mirip dengan ini. Salah satu pendekatan adalah menginterpolasi dari waktu animasi, ketinggian tampilan dari waktu ke waktu di dalam baris onMeasuresaat mengeluarkan requestLayout()untuk listView. Ya mungkin lebih baik dilakukan di dalam kode listView secara langsung tetapi itu adalah solusi cepat (itu terlihat bagus!)

Dori
sumber
0

Hanya berbagi pendekatan lain:

Pertama-tama atur android tampilan daftar : animateLayoutChanges menjadi true :

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

Kemudian saya menggunakan handler untuk menambahkan item dan memperbarui tampilan daftar dengan penundaan:

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;
}
Mina Samy
sumber