Android ListView Satırlarının Eklenmesi veya Kaldırılması Animasyonlu


212

İOS'ta, UITableView satırlarının eklenmesini ve kaldırılmasını canlandırmak için çok kolay ve güçlü bir tesis var , burada bir youtube videosundan varsayılan animasyonu gösteren bir klip var . Çevredeki satırların silinen satıra nasıl daraldığını unutmayın. Bu animasyon, kullanıcıların bir listede nelerin değiştiğini ve veriler değiştiğinde listede neye baktıklarını takip etmelerine yardımcı olur.

Android'de geliştirdiğimden beri, bir TableView'daki satırları tek tek canlandıracak eşdeğer bir tesis bulamadım . notifyDataSetChanged()Bağdaştırıcımı çağırmak ListView'ın içeriğini yeni bilgilerle derhal güncellemesine neden olur. Veri değiştiğinde içeri iten veya kayan yeni bir satırın basit bir animasyonunu göstermek istiyorum, ancak bunu yapmak için herhangi bir belgelenmiş yol bulamıyorum. Görünüşe göre LayoutAnimationController bunun işe yaraması için bir anahtar tutabilir, ancak ListView ( ApiDemo'nun LayoutAnimation2'ye benzer) bir LayoutAnimationController ayarladığımda ve öğeler görüntülendikten sonra bağdaştırıcımdaki öğeleri kaldırdığımda öğeler hemen kayboluyor .

Ayrıca kaldırıldığında tek bir öğeyi canlandırmak için aşağıdaki gibi şeyleri denedim:

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

Ancak, animasyonlu satırı çevreleyen satırlar notifyDataSetChanged()çağrıldığında yeni konumlarına atlayana kadar konumu hareket ettirmez . ListView, öğeleri yerleştirildikten sonra düzenini güncellemiyor gibi görünüyor.

ListView kendi uygulaması / çatal yazmak aklımdan geçti, bu çok zor olmamalı bir şey gibi görünüyor.

Teşekkürler!


Birisi bunun cevabını buldu mu? pls shareee
AndroidGecko

@Alex: bu youtube videosu (iphone gibi) gibi bir animasyon yaptınız mı, android için herhangi bir demo veya bağlantınız varsa lütfen bana verin, xml dosyasında animateLayoutChanges'i kullanmayı denedim, ancak tam olarak iphone gibi değil
Jayesh

@Jayesh, maalesef artık Android geliştirme üzerinde çalışmıyorum. 2012'den sonra yazılan bu sorunun cevabını test
etmedim

Yanıtlar:


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

yukarıdan aşağıya animasyon kullanımı için:

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

70
anim.setAnimationListener(new AnimationListener() { ... })Bir Handler kullanmak yerine kullanmak daha iyidir
Oleg Vaskevich

1
ne populateList()için?
Vasily Sochinsky

5
@MrAppleBR birkaç nedenden dolayı. İlk olarak, gereksiz bir şey yaratmıyorsunuz Handler. İkinci olarak, animasyon bittiğinde dahili bir geri arama kullanarak kodu daha az karmaşık hale getirir. Üçüncüsü, her platformun nasıl uygulanacağını bilmiyorsunuz Handlerve Animationher platformda çalışacaksınız; gecikmeli runnable'ınız animasyon bitmeden önce gerçekleşebilir.
Oleg Vaskevich

7
"Animasyonlu satırı çevreleyen satırlar, notifyDataSetChanged () çağrıldığında yeni konumlarına atlayana kadar konumu taşımaz." bu sorun hala çözümünüzde devam ediyor.
Boris Rusev

5
FavouritesManager sınıfı ve populateList () yöntemi nedir?
Jayesh

14

1
Basit bir animasyon gerektiğinde bu basit bir yol olduğunu düşünüyorum, ancak ayrıca RecyclerView.setItemAnimator () yöntemini kullanarak animasyon özelleştirebilirsiniz.
qatz

2
Son adım, sahip olduğum eksik bağlantı. kararlı kimlikler. Teşekkürler!
Amir Uval

Bu, API'yi iyi gösteren harika bir örnek projedir.
Mr-IDE


2

Yana ListViewsoldukça optimize edilmiştir ben bu accieve mümkün olmadığını düşünüyorum. "ListView" kodunuzu (yani satırlarınızı xml'den şişirip a'ya ekleyerek LinearLayout) oluşturmaya ve canlandırmaya çalıştınız mı ?


6
Sadece animasyon eklemek için liste görünümünü yeniden uygulamak mantıklı değil.
Macarse

Kesinlikle a'yı kullanabilirdim LinearLayout, ancak çok büyük veri kümelerinin LinearLayoutperformansı uçsuz bucaksız olacak. ListViewgörüntüleme geri dönüşümü etrafında büyük veri kümelerini işlemesine olanak tanıyan birçok akıllı optimizasyona sahiptir (iOS UITableView aynı optimizasyonlara sahiptir). Kendi görüşümü geri dönüştürücümü yazmak yeniden uygulama kategorisine giriyor ListView :(
Alex Pretzlav

Bunun mantıklı olmadığını biliyorum - ama sadece birkaç satırla çalışırsanız, güzel giriş / çıkış animasyonlarına sahip olmanın faydası denemeye değer olabilir.
whlk

2

Sağ taraftaki bir süpürmeyi canlandırmayı düşündünüz mü? Liste öğesinin üst kısmına giderek daha büyük bir beyaz çubuk çizmek, ardından listeden kaldırmak gibi bir şey yapabilirsiniz. Diğer hücreler hala sarsılacaktı, ama hiç olmamasından daha iyi olurdu.


2

listView.scheduleLayoutAnimation () işlevini çağırın; listeyi değiştirmeden önce


2

Liste görünümünü değiştirmek zorunda kalmadan bunu yapmanın başka bir yolunu hackledim. Ne yazık ki, düzenli Android Animasyonları satırın içeriğini değiştiriyor gibi görünüyor, ancak görünümü gerçekten küçültme konusunda etkisiz. Yani, önce bu işleyiciyi düşünün:

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

Bu koleksiyonu Liste bağdaştırıcınıza ekleyin:

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

ve Ekle

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

Ardından, bir satırı gizlemek istediğiniz her yere şunu ekleyin:

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

Bu kadar! Yüksekliği aynı anda daralttığı piksel sayısını değiştirerek animasyonun hızını değiştirebilirsiniz. Gerçek sofistike değil, ama işe yarıyor!


2

ListView'a yeni satır ekledikten sonra, ListView'ı yeni konuma kaydırıyorum.

ListView.smoothScrollToPosition(position);

1

Ben denemedim ama animateLayoutChanges aradığınızı yapmalı gibi görünüyor. ImageSwitcher sınıfında görüyorum, sanırım ViewSwitcher sınıfında mı?


Hey teşekkürler, buna bakacağım. Ne yazık ki animateLayoutChanges API Seviye 11 olarak yeni gibi görünüyor aka Honeycomb aka henüz herhangi bir telefonda bu kullanamazsınız :(
Alex Pretzlav

1

Android açık kaynak kodlu olduğu için ListView optimizasyonlarını yeniden uygulamanıza gerek yoktur. ListView kodunu alabilir ve animasyonda hacklemenin bir yolunu bulmaya çalışabilirsiniz, aynı zamanda android hata izleyicide bir özellik isteği de açabilirsiniz (ve uygulamaya karar verdiyseniz, bir yama eklemeyi unutmayın ).

Bilginize, ListView kaynak kodu burada .


1
Bu tür değişikliklerin uygulanması bu şekilde değildir. Her şeyden önce, liste görünümlerine animasyon eklemek için oldukça ağır bir yaklaşım olan AOSP proje binasına sahip olmalısınız. Lütfen çeşitli açık kaynak kütüphanelerindeki uygulamalara bakınız.
OrhanC1

1

İşte satırları silmenize ve yeniden sıralamanıza olanak tanıyan kaynak kodu .

Bir demo APK dosyası da mevcuttur. Satırların silinmesi, Google'ın Gmail uygulamasının üst satırını kaydırdıktan sonra alt görünümü gösteren satırlarında daha çok yapılır. Alt görünümde Geri Al düğmesi veya istediğiniz herhangi bir şey olabilir.


1

Sitemdeki yaklaşımımı açıkladığım gibi bağlantıyı paylaştım.Her zaman fikir getdrawingcache ile bitmapler oluşturmaktır. İki bitmap var ve hareketli efekti oluşturmak için alt bitmap'i canlandırın

Lütfen aşağıdaki koda bakın:

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

Görüntülerle anlamak için buna bakın

Teşekkürler.


0

Buna benzer bir şey yaptım. Bir yaklaşım, satır içinde zamanla animasyon süresi bakış yüksekliği boyunca sokmak için onMeasureverilmesi sırasında requestLayout()ListeGörünüm için. Evet listView kodunu doğrudan yapmak daha iyi olabilir, ancak hızlı bir çözümdü (iyi görünüyordu!)


0

Başka bir yaklaşımı paylaşmak:

Önce liste görünümünün android: animateLayoutChanges değerini true olarak ayarlayın :

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

Sonra öğeleri eklemek ve liste görünümünü gecikme ile güncellemek için bir işleyici kullanın:

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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.