RecyclerView öğeleri göründüklerinde nasıl canlandırılır?


237

Görünen yerde RecyclerView Öğelerini nasıl canlandırabilirim?

Varsayılan öğe animatörü, yalnızca geri dönüşüm verileri ayarlandıktan sonra bir veri eklendiğinde veya kaldırıldığında animasyon yapar. Ben yeni uygulamalar geliştiriyorum ve nereden başlayacağımı bilmiyorum.

Bunu nasıl başaracağınıza dair bir fikrin var mı?

Yanıtlar:


42

Yalnızca XML ile Basitleştirildi

Gist Link'i Ziyaret Edin

res / Anim / layout_animation.xml

<?xml version="1.0" encoding="utf-8"?>
    <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
        android:animation="@anim/item_animation_fall_down"
        android:animationOrder="normal"
        android:delay="15%" />

res / Anim / item_animation_fall_down.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500">

    <translate
        android:fromYDelta="-20%"
        android:toYDelta="0"
        android:interpolator="@android:anim/decelerate_interpolator"
        />

    <alpha
        android:fromAlpha="0"
        android:toAlpha="1"
        android:interpolator="@android:anim/decelerate_interpolator"
        />

    <scale
        android:fromXScale="105%"
        android:fromYScale="105%"
        android:toXScale="100%"
        android:toYScale="100%"
        android:pivotX="50%"
        android:pivotY="50%"
        android:interpolator="@android:anim/decelerate_interpolator"
        />

</set>

Yerleşimlerde kullanın ve şunun gibi yeniden görüntüleme:

<android.support.v7.widget.RecyclerView
                android:id="@+id/recycler_view"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layoutAnimation="@anim/layout_animation"
                app:layout_behavior="@string/appbar_scrolling_view_behavior" />

1
@ArnoldBrown Animasyon dosyasını değiştirerek. Bakınız: stackoverflow.com/questions/5151591/…
iamnaran

Bu açık ara en pratik cevap.
Oliver Metz

liste her açıldığında bu çalışmanın nasıl yapılacağı, çünkü şimdi sadece ilk defa yapıyor.
Hiwa Jalal

7
recyclerView.scheduleLayoutAnimation()Veri kümesi değiştikten sonra aramalısınız , aksi takdirde animasyon çalışmaz.
zeleven

Bu, öğeler geri dönüştürüldüğünde ve tekrar görüldüğünde işe yarar mı? Bu çözümü denedim ve ilk düzeni gördüğünüzde ilk animasyon için harika çalışıyor. Kaydırma yapıldıktan sonra, görüntülemeye geri döndüğünde öğeler animasyon içermiyor.
Jason p

315

DÜZENLE :

Göre ItemAnimator belgelerinde :

Bu sınıf, bağdaştırıcıda değişiklik yapıldıkça öğeler üzerinde gerçekleşen animasyonları tanımlar.

Öğelerinizi tek tek eklemediğiniz RecyclerViewve her yinelemede görünümü yenilediğiniz sürece ItemAnimator, ihtiyacınıza çözüm olduğunu düşünmüyorum .

RecyclerViewBir CustomAdapter kullanarak göründüklerinde öğeleri nasıl canlandırabileceğiniz aşağıda açıklanmıştır:

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder>
{
    private Context context;

    // The items to display in your RecyclerView
    private ArrayList<String> items;
    // Allows to remember the last item shown on screen
    private int lastPosition = -1;

    public static class ViewHolder extends RecyclerView.ViewHolder
    {
        TextView text;
        // You need to retrieve the container (ie the root ViewGroup from your custom_item_layout)
        // It's the view that will be animated
        FrameLayout container;

        public ViewHolder(View itemView)
        {
            super(itemView);
            container = (FrameLayout) itemView.findViewById(R.id.item_layout_container);
            text = (TextView) itemView.findViewById(R.id.item_layout_text);
        }
    }

    public CustomAdapter(ArrayList<String> items, Context context)
    {
        this.items = items;
        this.context = context;
    }

    @Override
    public CustomAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.custom_item_layout, parent, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position)
    {
        holder.text.setText(items.get(position));

        // Here you apply the animation when the view is bound
        setAnimation(holder.itemView, position);
    }

    /**
     * Here is the key method to apply the animation
     */
    private void setAnimation(View viewToAnimate, int position)
    {
        // If the bound view wasn't previously displayed on screen, it's animated
        if (position > lastPosition)
        {
            Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
            viewToAnimate.startAnimation(animation);
            lastPosition = position;
        }
    }
}

Ve custom_item_layout'unuz şöyle görünür:

<FrameLayout
    android:id="@+id/item_layout_container"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/item_layout_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceListItemSmall"
        android:gravity="center_vertical"
        android:minHeight="?android:attr/listPreferredItemHeightSmall"/>

</FrameLayout>

CustomAdapters hakkında daha fazla bilgi ve resmi belgeler hakkındakiRecyclerView bu eğitime bakın .

Hızlı kaydırma ile ilgili sorunlar

Bu yöntemi kullanmak hızlı kaydırma ile ilgili sorunlara neden olabilir. Animasyon yapılırken görünüm yeniden kullanılabilir. Bundan kaçınmak için, ayrıldığında animasyonu temizlemeniz önerilir.

    @Override
    public void onViewDetachedFromWindow(final RecyclerView.ViewHolder holder)
    {
        ((CustomViewHolder)holder).clearAnimation();
    }

CustomViewHolder'da:

    public void clearAnimation()
    {
        mRootLayout.clearAnimation();
    }

Eski cevap:

Gabriele Mariotti'nin deposuna bir bakın, ihtiyacınız olanı bulacağınızdan eminim. RecyclerView için SlideInItemAnimator veya SlideScaleItemAnimator gibi basit ItemAnimators sağlar.


1
Bunu gördüm, ancak bunlar ortaya çıktıktan sonra öğeleri eklemek ve kaldırmak için. Görünmeden hemen önce animasyonu başlatmalıyım. Yine de teşekkürler Mathieu.
PaulNunezM

1
Bildiğim kadarıyla, bir CustomAdapter kullanmanız gerekiyor.
MathieuMaree

20
RecyclerView'de bu animasyonlarla "sıkışmış" efekti deneyimlemiş ve çözüp çözmediğinizi merak ediyordum. ListView için benzer kod kullandım ve öğelerim ne kadar hızlı kaydırsam da önemli değil, ancak RecyclerView ile hızlı kaydırırsam bazı öğeler bazen diğer öğelerin üstünde ekrana yapışır ve tamamen gizlenmezler - animasyon bitmeden durdurulmuş gibi. Aslında (onBindViewHolder yönteminin yürütülmesini hızlandırmak için çalışıyor) alanları doldurur kod parçası yorum yapmaya çalıştım, bu yüzden sadece animat için kod bıraktı
Tomislav

4
@MathieuMaree Bu şaşkınlık animasyon için teşekkürler.Yavaş kaydırma için iyi görünüyor, ancak hızlı kaydırma geri dönüşüm görüntüleme öğeleri örtüşüyor.
Giru Bhai

40
@GiruBhai geçersiz kılın onViewDetachedFromWindowve clearAnimationgörünümü çağırın . Sorun RecyclerView görünümü yeniden kullanmaya çalışırken animasyonlar çalışıyor olmasıdır.
Xample

62

RecyclerviewAşağıdaki kodda gösterildiği gibi ilk göründüklerinde öğelerin solmasını canlandırdım . Belki bu birisi için yararlı olacaktır.

private final static int FADE_DURATION = 1000; //FADE_DURATION in milliseconds

@Override
public void onBindViewHolder(ViewHolder holder, int position) {

    holder.getTextView().setText("some text");

    // Set the view to fade in
    setFadeAnimation(holder.itemView);            
}

private void setFadeAnimation(View view) {
    AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
    anim.setDuration(FADE_DURATION);
    view.startAnimation(anim);
}

Ayrıca , bir noktadan ölçekleyerek öğelerin görünümlerini canlandırmak setFadeAnimation()için aşağıdakilerle değiştirebilirsiniz setScaleAnimation():

private void setScaleAnimation(View view) {
    ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    anim.setDuration(FADE_DURATION);
    view.startAnimation(anim);
}

Yukarıdaki kod, RecyclerViewöğeleri her zaman soluklaştığında veya ölçeklendirdiğinizde bazı siğiller içerir . İsterseniz, animasyonu içeren parça veya etkinlik RecyclerViewilk oluşturulduğunda gerçekleşmesine izin vermek için kod ekleyebilirsiniz (örn. Oluşturma sırasında sistem zamanını alın ve yalnızca ilk FADE_DURATION milisaniye için animasyona izin verin).


1
Ben, sadece aşağı kaydırma üzerinde animasyon çalışması kontrol etmek Cevabınız için küçük bir değişiklik yaptım benim cevap
Basheer AL-MOMANI

1
Bu, hızlı yukarı ve aşağı kaydırma düzenini (aşırı yazılmış liste öğeleri, bazı öğeler yanlış metin rengine sahip)
bozar

Bu, geri dönüşüm görüntüleme öğelerini canlandırmanın uygun veya önerilen yolu değildir. ItemAnimator sınıfını kullanıyor olmanız gerekir
Eco4ndly

25

Pbm'nin cevabından animasyonla çok azmodification aninmation çalışmasını sadece bir kez yapmak

diğer bir deyişle Animation appear with you scroll down only

private int lastPosition = -1;

private void setAnimation(View viewToAnimate, int position) {
    // If the bound view wasn't previously displayed on screen, it's animated
    if (position > lastPosition) {
        ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        anim.setDuration(new Random().nextInt(501));//to make duration random number between [0,501)
        viewToAnimate.startAnimation(anim);
        lastPosition = position;
    }
}

ve onBindViewHolderfonksiyon çağrısında

@Override
public void onBindViewHolder(ViewHolder holder, int position) {

holder.getTextView().setText("some text");

// call Animation function
setAnimation(holder.itemView, position);            
}

1
Burada lastPosition nedir? ArrayList.size () - 1
Sumit Shukla

1
lastPositiongörüntülenen görüntüleme sayısını temsil eder, bu nedenle değeri başlar -1, her yeni görünüm oluşturulduğunda bir animasyon başlatıyoruz ve konumu artırıyoruz
Basheer AL-MOMANI

15

Buna benzer bir android:layoutAnimation="@anim/rv_item_animation"özellik ekleyebilirsiniz RecyclerView:

<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"                                        
    android:layoutAnimation="@anim/layout_animation_fall_down"
    />

Buradaki mükemmel makale için teşekkürler: https://proandroiddev.com/enter-animation-using-recyclerview-and-layoutanimation-part-1-list-75a874a5d213


Bu, bir geri dönüşüm görünümü ilk yüklendiğinde benim için çalıştı, ancak yeni öğeler eklerken değil. (Sanırım bu çok iyi bir işti)
C. Skjerdal

8

Başlamak için iyi bir yer şudur: https://github.com/wasabeef/recyclerview-animators/blob/master/animators/src/main/java/jp/wasabeef/recyclerview/adapters/AnimationAdapter.java

Tam kütüphaneye bile ihtiyacınız yok, bu sınıf yeterli. Öyleyse, sadece böyle bir animatör vererek Adapter sınıfınızı uygularsanız:

@Override
protected Animator[] getAnimators(View view) {
    return new Animator[]{
            ObjectAnimator.ofFloat(view, "translationY", view.getMeasuredHeight(), 0)
    };
}

@Override
public long getItemId(final int position) {
    return getWrappedAdapter().getItemId(position);
}

öğeleri kaydırdıkça alttan görerek hızlı kaydırma sorununu da göreceksiniz.


3

Bağdaştırıcıya bağlandıklarında geri dönüşüm görünümündeki öğeleri canlandırmak en iyi fikir olmayabilir, çünkü geri dönüşüm görünümündeki öğelerin farklı hızlarda canlandırılmasına neden olabilir. Benim durumumda, geri dönüşüm görünümünün sonundaki öğe konumlarına daha hızlı hareket eder, daha sonra üstteki olanlar daha fazla seyahat eder, bu yüzden düzensiz görünmesini sağlar.

Her öğeyi geri dönüşüm görünümüne hareketlendirmek için kullandığım orijinal kodu burada bulabilirsiniz:

http://frogermcs.github.io/Instagram-with-Material-Design-concept-is-getting-real/

Ancak bağlantı kopması durumunda kodu kopyalayıp yapıştıracağım.

ADIM 1: Animasyonun yalnızca bir kez çalışmasını sağlamak için bunu onCreate yönteminizde ayarlayın:

if (savedInstanceState == null) {
    pendingIntroAnimation = true;
}

ADIM 2: Bu kodu animasyonu başlatmak istediğiniz yönteme koymanız gerekir:

if (pendingIntroAnimation) {
    pendingIntroAnimation = false;
    startIntroAnimation();
}

Bağlantıda, yazar araç çubuğu simgelerini canlandırıyor, bu yüzden onu bu yöntemin içine koydu:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_main, menu);
    inboxMenuItem = menu.findItem(R.id.action_inbox);
    inboxMenuItem.setActionView(R.layout.menu_item_view);
    if (pendingIntroAnimation) {
        pendingIntroAnimation = false;
        startIntroAnimation();
    }
    return true;
}

ADIM 3: Şimdi startIntroAnimation () mantığını yazın:

private static final int ANIM_DURATION_TOOLBAR = 300;

private void startIntroAnimation() {
    btnCreate.setTranslationY(2 * getResources().getDimensionPixelOffset(R.dimen.btn_fab_size));

    int actionbarSize = Utils.dpToPx(56);
    toolbar.setTranslationY(-actionbarSize);
    ivLogo.setTranslationY(-actionbarSize);
    inboxMenuItem.getActionView().setTranslationY(-actionbarSize);

    toolbar.animate()
            .translationY(0)
            .setDuration(ANIM_DURATION_TOOLBAR)
            .setStartDelay(300);
    ivLogo.animate()
            .translationY(0)
            .setDuration(ANIM_DURATION_TOOLBAR)
            .setStartDelay(400);
    inboxMenuItem.getActionView().animate()
            .translationY(0)
            .setDuration(ANIM_DURATION_TOOLBAR)
            .setStartDelay(500)
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    startContentAnimation();
                }
            })
            .start();
}

Tercih ettiğim alternatif:

Ben recyclerview içindeki öğeler yerine tüm recyclerview animasyon.

ADIM 1 ve 2 aynı kalır.

3. ADIM'da, API çağrınız verilerinizle birlikte gelir gelmez animasyonu başlatacağım.

private void startIntroAnimation() {
    recyclerview.setTranslationY(latestPostRecyclerview.getHeight());
    recyclerview.setAlpha(0f);
    recyclerview.animate()
            .translationY(0)
            .setDuration(400)
            .alpha(1f)
            .setInterpolator(new AccelerateDecelerateInterpolator())
            .start();
}

Bu, ekranın altından içeri girmesi için tüm geri dönüşüm görünümünüzü canlandırır.


bütün geri dönüşüm
görüntüsünü

Evet benim. Tüm geri dönüşüm görünümünü görüntülemenin neden her öğeden daha iyi bir fikir olduğunu düşündüğümün ilk paragrafını okumalısınız. Her öğeyi canlandırmayı deneyebilirsiniz, ancak iyi görünmeyecektir.
Simon

Nedir latestPostRecyclerview?
Antonio

1
Öğe görünümlerini canlandırmanın neden bu kadar iyi bir fikir olmadığını açıkladığım cevabımın ilk paragrafını okudunuz mu? Ayrıca kabul edilen çözümü denemenizi öneririm ve sonra sorunu fark edersiniz, geri dönün ve bu çözümü deneyin.
Simon

3

Bu yöntemi geri dönüşüm görüntüleme Bağdaştırıcınızda oluşturun

private void setZoomInAnimation(View view) {
        Animation zoomIn = AnimationUtils.loadAnimation(context, R.anim.zoomin);// animation file 
        view.startAnimation(zoomIn);
    }

Ve son olarak bu kod satırını onBindViewHolder'a ekleyin

setZoomInAnimation(holder.itemView);


2

2019'da, tüm öğe animasyonlarını ItemAnimator'a koymanızı öneririm.

Animatörü geri dönüşüm görünümünde ilan etmekle başlayalım:

with(view.recycler_view) {
adapter = Adapter()
itemAnimator = CustomAnimator()
}

Özel animatörü ilan edin,

class CustomAnimator() : DefaultItemAnimator() {

     override fun animateAppearance(
       holder: RecyclerView.ViewHolder,
       preInfo: ItemHolderInfo?,
       postInfo: ItemHolderInfo): Boolean{} // declare  what happens when a item appears on the recycler view

     override fun animatePersistence(
       holder: RecyclerView.ViewHolder,
       preInfo: ItemHolderInfo,
       postInfo: ItemHolderInfo): Boolean {} // declare animation for items that persist in a recycler view even when the items change

}

Yukarıdaki olanlara benzer şekilde, yok olma animateDisappearance, ekleme animateAdd, değişim animateChangeve hareket için bir tane var animateMove.

Önemli bir nokta, içlerine doğru animasyon dağıtım programlarını çağırmak olacaktır.


Bu geçersiz kılma işlevini kullanarak özel bir görünüm animasyonu örneği verebilir misiniz? Bir örnek bulamıyorum ve ben sadece fonksiyonda animasyon belirtmek zorunda olup olmadığından emin değilim.
minaresi

1
gist.github.com/tadfisher/120d03f8380bfa8a16bf Bunu hızlı bir aramada çevrimiçi buldum, bu aşırı yüklenmenin nasıl çalıştığı hakkında bir fikir veriyor
Dinesh

0

Adaptörünüzü aşağıdaki gibi uzatmanız yeterlidir

public class RankingAdapter extends AnimatedRecyclerView<RankingAdapter.ViewHolder> 

Ve onBindViewHolder'a süper yöntem ekleyin

@Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
        super.onBindViewHolder(holder, position);

"Basheer AL-MOMANI" gibi animasyonlu adaptör oluşturmanın otomatik yolu

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;

import java.util.Random;

/**
 * Created by eliaszkubala on 24.02.2017.
 */
public class AnimatedRecyclerView<T extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<T> {


    @Override
    public T onCreateViewHolder(ViewGroup parent, int viewType) {
        return null;
    }

    @Override
    public void onBindViewHolder(T holder, int position) {
        setAnimation(holder.itemView, position);
    }

    @Override
    public int getItemCount() {
        return 0;
    }

    protected int mLastPosition = -1;

    protected void setAnimation(View viewToAnimate, int position) {
        if (position > mLastPosition) {
            ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            anim.setDuration(new Random().nextInt(501));//to make duration random number between [0,501)
            viewToAnimate.startAnimation(anim);
            mLastPosition = position;
        }
    }

}

0

Bence, bu şekilde kullanmak daha iyidir: (RecyclerView bağdaştırıcısında sadece bir yöntemi geçersiz kılar)

override fun onViewAttachedToWindow(holder: ViewHolder) {
    super.onViewAttachedToWindow(holder)

    setBindAnimation(holder)
}

RV'de her ekleme animasyonunu istiyorsanız.

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.