Cara menghidupkan item RecyclerView saat muncul

237

Bagaimana saya bisa menghidupkan Item RecyclerView ketika ada muncul?

Animator item default hanya akan hidup ketika data ditambahkan atau dihapus setelah data pendaur ulang telah ditetapkan. Saya baru mengembangkan aplikasi dan tidak tahu harus mulai dari mana.

Adakah ide bagaimana mencapai ini?

PaulNunezM
sumber

Jawaban:

42

Dimudahkan dengan XML saja

Kunjungi Gist Link

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>

Gunakan dalam layout dan recylcerview seperti:

<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" />
iamnaran
sumber
1
@ArnoldBrown Dengan mengubah file animasi. Lihat: stackoverflow.com/questions/5151591/…
iamnaran
Sejauh ini, inilah jawaban yang paling praktis.
Oliver Metz
cara membuat ini berfungsi setiap kali daftar dibuka, karena sekarang hanya melakukannya untuk pertama kalinya.
Hiwa Jalal
7
Anda harus menelepon recyclerView.scheduleLayoutAnimation()setelah kumpulan data berubah, jika tidak, animasi tidak akan berfungsi.
zeleven
Haruskah ini bekerja ketika barang didaur ulang dan kembali terlihat? Saya mencoba solusi ini dan ini berfungsi baik untuk animasi awal ketika Anda pertama kali dapat melihat tata letaknya. Setelah menggulir, item tidak memiliki animasi saat kembali untuk melihat.
Jason p
315

EDIT:

Menurut dokumentasi ItemAnimator :

Kelas ini mendefinisikan animasi yang terjadi pada item saat perubahan dilakukan ke adaptor.

Jadi, kecuali Anda menambahkan item Anda satu per satu ke Anda RecyclerViewdan menyegarkan tampilan di setiap iterasi, saya tidak berpikir ItemAnimatoradalah solusi untuk kebutuhan Anda.

Inilah cara Anda dapat menganimasikan RecyclerViewitem ketika item tersebut muncul menggunakan CustomAdapter:

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

Dan custom_item_layout Anda akan terlihat seperti ini:

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

Untuk informasi lebih lanjut tentang CustomAdapters dan RecyclerView, lihat pelatihan ini di dokumentasi resmi .

Masalah pada scroll cepat

Menggunakan metode ini dapat menyebabkan masalah dengan pengguliran cepat. Tampilan dapat digunakan kembali saat animasi sedang terjadi. Untuk menghindari itu, disarankan untuk menghapus animasi ketika dilepaskan.

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

Di CustomViewHolder:

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

Jawaban lama:

Lihatlah repo Gabriele Mariotti , saya cukup yakin Anda akan menemukan yang Anda butuhkan. Dia menyediakan ItemAnimators sederhana untuk RecyclerView, seperti SlideInItemAnimator atau SlideScaleItemAnimator.

MathieuMaree
sumber
1
Saya pernah melihatnya, tapi itu untuk menambah dan menghapus item setelah muncul. Saya perlu memulai animasi tepat sebelum muncul d. Terima kasih, Mathieu.
PaulNunezM
1
Sejauh yang saya tahu, Anda harus menggunakan CustomAdapter.
MathieuMaree
20
Saya bertanya-tanya apakah Anda pernah mengalami dan mungkin menyelesaikan efek "macet" dengan animasi ini di RecyclerView? Saya menggunakan kode serupa untuk ListView dan item saya dianimasikan tanpa masalah tidak peduli seberapa cepat saya menggulir, tetapi dengan RecyclerView jika saya menggulir cepat beberapa item kadang-kadang terjebak di layar di atas item lainnya dan mereka tidak bersembunyi sepenuhnya - Ini seperti animasi dihentikan sebelum selesai. Saya benar-benar mencoba untuk mengomentari bagian dari kode yang mengisi bidang (mencoba untuk mempercepat pelaksanaan metode onBindViewHolder) jadi saya hanya meninggalkan kode untuk animat
Tomislav
4
@MathieuMaree Terima kasih atas animasi yang menakjubkan ini. Ini terlihat bagus untuk scroll yang lambat, tetapi pada item recyclerview scroll cepat tumpang tindih. Apakah Anda menemukan penerbitan ini? Ada saran untuk mengatasi masalah ini.
Giru Bhai
40
@GiruBhai mengesampingkan onViewDetachedFromWindowdan memanggil clearAnimationtampilan. Masalahnya adalah bahwa ada animasi yang berjalan ketika RecyclerView mencoba menggunakan kembali tampilan.
Xample
62

Saya animasi memudar Recyclerviewitem ketika pertama kali muncul seperti yang ditunjukkan pada kode di bawah ini. Mungkin ini akan berguna bagi seseorang.

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

Anda juga dapat mengganti setFadeAnimation()dengan yang berikut ini setScaleAnimation()untuk menghidupkan tampilan item dengan menskalakannya dari suatu titik:

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

Kode di atas memiliki beberapa kutil sejauh ketika Anda menggulir RecyclerViewitem selalu pudar atau bersisik. Jika mau, Anda dapat menambahkan kode untuk memungkinkan animasi terjadi ketika fragmen atau aktivitas yang berisi RecyclerViewpertama kali dibuat (mis., Dapatkan waktu sistem saat pembuatan dan hanya izinkan animasi untuk milidetik FADE_DURATION pertama).

pbm
sumber
1
Saya melakukan sedikit modifikasi untuk jawaban Anda untuk membuat animasi bekerja hanya pada scroll ke bawah, periksa jawaban saya
Basheer AL-MOMANI
1
ini merusak tata letak (item daftar tertulis, beberapa item memiliki warna teks yang salah) pada scrolling cepat ke atas dan ke bawah
mrid
Ini bukan cara yang tepat atau direkomendasikan untuk menghidupkan barang-barang recyclerview. Anda harus menggunakan kelas
ItemAnimator
25

Saya membuat animasi dari jawaban pbm dengan sedikit modificationuntuk membuat informasi hanya berjalan satu kali

dengan kata lain 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;
    }
}

dan onBindViewHolderfungsi panggilan

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

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

// call Animation function
setAnimation(holder.itemView, position);            
}
Basheer AL-MOMANI
sumber
1
Apa posisi terakhir di sini? Apakah itu arrayList.size () - 1
Sumit Shukla
1
lastPositionmewakili jumlah tampilan yang diberikan, jadi ini adalah awal nilainya -1, setiap kali tampilan baru ditampilkan, kami memulai animasi dan meningkatkan posisi
Basheer AL-MOMANI
15

Anda dapat menambahkan android:layoutAnimation="@anim/rv_item_animation"atribut RecyclerViewseperti ini:

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

terima kasih untuk artikel yang sangat bagus di sini: https://proandroiddev.com/enter-animation-using-recyclerview-and-layoutanimation-part-1-list-75a874a5d213

Pavel Biryukov
sumber
Ini bekerja untuk saya ketika recyclerview pertama kali dimuat, tetapi tidak ketika menambahkan item baru. (Meskipun saya kira itu adalah pertanyaan pekerjaan yang sangat baik)
C. Skjerdal
8

Tempat yang baik untuk memulai adalah ini: https://github.com/wasabeef/recyclerview-animators/blob/master/animators/src/main/java/jp/wasabeef/recyclerview/adapters/AnimationAdapter.java

Anda bahkan tidak perlu perpustakaan lengkap, kelas itu sudah cukup. Kemudian jika Anda hanya mengimplementasikan kelas Adaptor Anda memberikan animator seperti ini:

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

Anda akan melihat item muncul dari bawah saat mereka menggulir, juga menghindari masalah dengan gulungan cepat.

Alessandro Crugnola
sumber
3

Animasi item di recyclerview ketika mereka diikat di adaptor mungkin bukan ide terbaik karena hal itu dapat menyebabkan item dalam recyclerview hidup dengan kecepatan yang berbeda. Dalam kasus saya, item pada akhir recyclerview menghidupkan posisi mereka lebih cepat daripada yang di atas sebagai yang di atas harus lebih jauh untuk bepergian sehingga membuatnya tampak berantakan.

Kode asli yang saya gunakan untuk menganimasikan setiap item ke dalam recyclerview dapat ditemukan di sini:

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

Tapi saya akan menyalin dan menempelkan kode jika tautan rusak.

LANGKAH 1: Setel ini di dalam metode onCreate Anda sehingga Anda memastikan animasi hanya berjalan sekali:

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

LANGKAH 2: Anda harus memasukkan kode ini ke metode di mana Anda ingin memulai animasi:

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

Di tautan, penulis menghidupkan ikon ikon bilah alat, jadi ia memasukkannya ke dalam metode ini:

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

LANGKAH 3: Sekarang tulis logika untuk startIntroAnimation ():

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

Alternatif pilihan saya:

Saya lebih suka menghidupkan seluruh recyclerview daripada barang-barang di dalam recyclerview.

LANGKAH 1 dan 2 tetap sama.

Di LANGKAH 3, segera setelah panggilan API Anda kembali dengan data Anda, saya akan memulai animasi.

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

Ini akan menghidupkan seluruh tinjauan ulang Anda sehingga dapat terbang dari bagian bawah layar.

Simon
sumber
Anda berbicara tentang menjiwai seluruh recyclerview
Longerian
Ya. Anda harus membaca paragraf pertama tentang mengapa saya pikir menjiwai seluruh recyclerview adalah ide yang lebih baik daripada setiap item. Anda dapat mencoba menghidupkan setiap item tetapi itu tidak akan terlihat bagus.
Simon
Apa latestPostRecyclerview?
Antonio
1
Apakah Anda membaca paragraf pertama dari jawaban saya di mana saya telah menyatakan alasan mengapa menjiwai tampilan item bukan ide yang bagus? Saya juga akan menyarankan mencoba solusi yang diterima dan kemudian Anda menyadari masalahnya, kembali dan coba solusi ini.
Simon
3

Buat metode ini ke dalam Adaptor daur ulang Anda

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

Dan akhirnya tambahkan baris kode ini di onBindViewHolder

setZoomInAnimation(holder.itemView);

Md.Tarikul Islam
sumber
2

Pada tahun 2019, saya akan menyarankan untuk memasukkan semua animasi item ke dalam ItemAnimator.

Mari kita mulai dengan mendeklarasikan animator dalam tampilan pendaur ulang:

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

Deklarasikan animator khusus itu,

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

}

Mirip dengan yang di atas ada satu untuk menghilang animateDisappearance, untuk menambah animateAdd, untuk mengubah animateChangedan memindahkananimateMove .

Satu poin penting adalah memanggil animasi-dispatcher yang benar di dalamnya.

Dinesh
sumber
Bisakah Anda memberikan contoh animasi tampilan khusus menggunakan fungsi override ini? Saya tidak dapat menemukan contoh dan saya tidak yakin apakah saya hanya perlu menentukan animasi dalam fungsinya.
minar
1
gist.github.com/tadfisher/120d03f8380bfa8a16bf Saya menemukan ini daring pada pencarian cepat, ini memberikan gambaran tentang cara kerja overloading
Dinesh
0

Perluas adaptor Anda seperti di bawah ini

public class RankingAdapter extends AnimatedRecyclerView<RankingAdapter.ViewHolder> 

Dan tambahkan metode super ke onBindViewHolder

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

Ini adalah cara otomatis untuk membuat adaptor animasi seperti "Basheer AL-MOMANI"

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

}
Eliasz Kubala
sumber
0

Saya pikir, lebih baik menggunakannya seperti ini: (dalam adaptor RecyclerView timpa hanya satu metode)

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

    setBindAnimation(holder)
}

Jika Anda ingin setiap lampiran animasi ada di RV.

Milan Jurkulak
sumber