जब वे दिखाई देते हैं तो RecyclerView आइटम को चेतन कैसे करें


237

जब मैं दिखाई दे रहा हूं तो मैं RecyclerView आइटम को कैसे एनिमेट कर सकता हूं?

डिफ़ॉल्ट आइटम एनिमेटर केवल तब ही एनिमेट करता है जब रिसाइकलर डेटा सेट होने के बाद डेटा जोड़ा या हटाया जाता है। मैं नए विकासशील एप्लिकेशन हूं और जहां शुरू करने के लिए कोई सुराग नहीं है।

किसी भी विचार यह कैसे प्राप्त करने के लिए?

जवाबों:


42

केवल XML के साथ सरल बनाया गया

Gist लिंक पर जाएं

रेस / 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%" />

रेस / 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>

लेआउट और पुनरावृत्ति में उपयोग करें जैसे:

<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 एनीमेशन फ़ाइल को बदलकर। देखें: stackoverflow.com/questions/5151591/…
iamnaran

यह अब तक का सबसे व्यावहारिक जवाब है।
ओलिवर मेट्ज़

हर बार सूची खोलने के बाद यह काम कैसे करें, क्योंकि अब यह केवल पहली बार ही करता है।
हियुवा जलाल

7
recyclerView.scheduleLayoutAnimation()डेटा सेट बदलने के बाद आपको कॉल करना होगा, यदि नहीं, तो एनीमेशन काम नहीं करेगा।

जब आइटम पुनर्नवीनीकरण किए जाते हैं और वापस देखने में आते हैं तो क्या यह काम करना चाहिए? मैंने इस समाधान का प्रयास किया और यह प्रारंभिक एनीमेशन के लिए बहुत अच्छा काम करता है जब आप पहली बार लेआउट देख सकते हैं। स्क्रॉल करने के बाद, आइटम को देखने के लिए वापस आने पर एनीमेशन नहीं होता है।
जेसन पी

315

संपादित करें:

ItemAnimator प्रलेखन के अनुसार :

यह वर्ग एडॉप्टर में किए गए परिवर्तनों के अनुसार वस्तुओं पर होने वाले एनिमेशन को परिभाषित करता है।

इसलिए जब तक आप अपने आइटमों को एक-एक करके जोड़ते हैं RecyclerViewऔर प्रत्येक पुनरावृत्ति पर दृश्य को ताज़ा करते हैं, मुझे नहीं लगता कि ItemAnimatorआपकी ज़रूरत का समाधान है।

RecyclerViewजब आप 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;
        }
    }
}

और आपका custom_item_layout इस तरह दिखेगा:

<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 के बारे में अधिक जानकारी के लिए और RecyclerView, आधिकारिक दस्तावेज पर इस प्रशिक्षण को देखें ।

तेज स्क्रॉल पर समस्याएं

इस विधि के उपयोग से तेज स्क्रॉलिंग की समस्या हो सकती है। एनीमेशन का उपयोग करते समय दृश्य का पुन: उपयोग किया जा सकता है। से बचने के लिए कि अलग होने पर एनीमेशन को खाली करने की सिफारिश की जाती है।

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

CustomViewHolder पर:

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

पुराना उत्तर:

गैब्रिएल मैरीओटी के रेपो पर एक नज़र डालें , मुझे पूरा यकीन है कि आपको वह मिलेगा जो आपको चाहिए। वह पुनर्नवीकरण के लिए सरल ItemAnimators प्रदान करता है, जैसे SlideInItemAnimator या SlideScaleItemAnimator।


1
मैंने देखा है कि, लेकिन वे आइटम जोड़ने और हटाने के बाद दिखाई दिए हैं। मैं सही शुरू होने से पहले एनीमेशन शुरू करने की जरूरत है। वैसे भी धन्यवाद मैथ्यू।
पॉल न्यूनज़्म

1
जहाँ तक मुझे पता है, आपको तब एक CustomAdapter का उपयोग करने की आवश्यकता है।
मैथ्यूमैरी

20
मैं सोच रहा था कि क्या आपने अनुभव किया है और शायद RecyclerView में इन एनिमेशन के साथ "अटक" प्रभाव को हल किया है? मैंने ListView के लिए समान कोड का उपयोग किया था और मेरे आइटम एक समस्या के बिना एनिमेटेड थे, चाहे मैं कितनी भी तेज़ी से स्क्रॉल करूं, लेकिन अगर मैं तेजी से स्क्रॉल करता हूं तो कुछ आइटम कभी-कभी स्क्रीन पर अन्य वस्तुओं के ऊपर अटक जाते हैं और वे पूरी तरह से छिपते नहीं हैं - ऐसा लगता है कि एनीमेशन समाप्त होने से पहले ही रोक दिया गया था। मैंने वास्तव में कोड के उस हिस्से को कमेंट करने की कोशिश की जो खेतों को आबाद करता है (onBindViewHolder मेथड के निष्पादन में तेजी लाने की कोशिश कर रहा है) इसलिए मैंने केवल एनिमेट के लिए कोड छोड़ा है
Tomislav

4
@MathieuMaree इस विस्मयकारी एनीमेशन के लिए धन्यवाद। यह धीमी स्क्रॉल के लिए अच्छा लग रहा है, लेकिन फास्ट स्क्रॉल recyclerview आइटम पर ओवरलैप किया गया है। क्या आपको यह issse मिल गया है? इस मुद्दे को दूर करने के लिए कोई सुझाव।
गिरु भाई

40
@GiruBhai ओवरराइड onViewDetachedFromWindowकरें और clearAnimationव्यू पर कॉल करें । समस्या यह है कि ऐसे एनिमेशन चल रहे हैं जब RecyclerView दृश्य का पुन: उपयोग करने की कोशिश कर रहा है।
Xample

62

Recyclerviewजब वे पहली बार नीचे दिए गए कोड में दिखाए गए हैं, तो मैं आइटमों का एनिमेटेड लुप्त होती हूं । शायद यह किसी के काम आएगा।

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

आप एक बिंदु से स्केल करके आइटम के चेतन रूप को setFadeAnimation()निम्नलिखित के साथ बदल सकते हैं 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);
}

ऊपर दिए गए कोड में कुछ मौसा होते हैं जब तक आप RecyclerViewआइटम को हमेशा फीका या पैमाने पर स्क्रॉल करते हैं । यदि आप चाहते हैं कि आप कोड जोड़ सकते हैं तो केवल एनीमेशन को होने दें जब टुकड़ा या गतिविधि RecyclerViewपहली बार बनाई जाती है (उदाहरण के लिए निर्माण पर सिस्टम समय प्राप्त करें और केवल पहले FADE_DURATION मिलीसेकंड के लिए एनीमेशन की अनुमति दें)।


1
मैंने आपके उत्तर के लिए छोटे संशोधन को केवल स्क्रॉल डाउन पर एनीमेशन का काम करने के लिए किया, मेरे उत्तर की
बशीर अल-मोमानी

1
यह तेजी से स्क्रॉल अप और डाउन पर लेआउट (ओवर-लिखित सूची आइटम, कुछ आइटम गलत पाठ रंग वाले) को
खराब करता है

यह recyclerview आइटम को चेतन करने का उचित या अनुशंसित तरीका नहीं है। आप ItemAnimator क्लास
Eco4ndly

25

मैं एक बार केवल रन बनाने के लिए थोड़ा के साथ pbm के जवाब से एनीमेशन बनायाmodification

दूसरे शब्द में 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;
    }
}

और onBindViewHolderफ़ंक्शन को कॉल करें

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

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

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

1
आखिर क्या है यहां? क्या यह व्यूह है। इसे लाइए। (1) - 1
सुमित शुक्ला

1
lastPositionप्रस्तुत किए गए विचारों की संख्या का प्रतिनिधित्व करता है, इसलिए यह इसकी कीमत की शुरुआत करता है -1, हर बार एक नया दृश्य प्रदान किया जा रहा है हम एक एनीमेशन शुरू करते हैं और स्थिति को बढ़ाते हैं
बशीर अल-मोमानी

15

आप इस तरह android:layoutAnimation="@anim/rv_item_animation"से एक विशेषता जोड़ सकते हैं RecyclerView:

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

यहाँ उत्कृष्ट लेख के लिए धन्यवाद: https://proandroiddev.com/enter-animation-using-recyclerview-and-layoutanimation-part-1-list-75a874a5d213


यह मेरे लिए तब काम आया जब एक रिसाइकलव्यू पहली बार लोड हुआ, लेकिन नए आइटम जोड़ने पर नहीं। (हालांकि मुझे लगता है कि यह सवाल इतना अच्छा काम था)
सी। स्केजेरालल

8

शुरू करने के लिए एक अच्छी जगह यह है: https://github.com/wasabeef/recyclerview-animators/blob/master/animators/src/main/java/jp/wasabeef/recyclerview/adapters/AnimationAdapter.java

आपको पूर्ण पुस्तकालय की भी आवश्यकता नहीं है, वह वर्ग पर्याप्त है। फिर अगर आप इस तरह से एक एनिमेटर देने वाले अपने एडॉप्टर वर्ग को लागू करते हैं:

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

आप नीचे स्क्रॉल करते हुए दिखाई देने वाली वस्तुओं को देखेंगे, वे भी तेज स्क्रॉल के साथ समस्या से बचते हैं।


3

जब वे एडेप्टर में बंधे होते हैं तो रिसाइकलव्यू में एनिमेटेड आइटम सबसे अच्छा विचार नहीं हो सकता है क्योंकि यह अलग-अलग गति से चेतन करने के लिए recyclerview में आइटम का कारण बन सकता है। मेरे मामले में, रिसाइकलव्यू के अंत में आइटम अपनी स्थिति को फिर से चेतन करता है फिर सबसे ऊपर वाले को क्योंकि शीर्ष पर आने वाले लोग यात्रा करने के लिए आगे बढ़ते हैं, इसलिए यह अस्वच्छ दिखाई देता है।

मूल कोड जिसे मैंने प्रत्येक आइटम को recyclerview में चेतन करने के लिए इस्तेमाल किया था, वह यहाँ पाया जा सकता है:

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

लेकिन मैं लिंक को तोड़ने के मामले में कोड को कॉपी और पेस्ट करूंगा।

चरण 1: इसे अपने ऑनक्रीट विधि के अंदर सेट करें ताकि आप एनीमेशन को केवल एक बार चलाना सुनिश्चित करें:

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

चरण 2: आपको इस कोड को उस विधि में डालना होगा जहां आप एनीमेशन शुरू करना चाहते हैं:

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

लिंक में, लेखक टूलबार आइकन को एनिमेट कर रहा है, इसलिए उसने इसे इस विधि के अंदर रखा:

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

चरण 3: अब 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();
}

मेरा पसंदीदा विकल्प:

मैं पूरी तरह से recyclerview अंदर आइटम के बजाय पूरे recyclerview चेतन होगा।

STEP 1 और 2 ही रहता है।

STEP 3 में, जैसे ही आपका API आपके डेटा के साथ कॉल करता है, मैं एनीमेशन शुरू कर दूंगा।

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

यह आपके पूरे रिसाइकिलव्यू को चेतन करेगा ताकि यह स्क्रीन के नीचे से उड़ जाए।


आप पूरे recyclerview
Longerian

हाँ मैं हूँ। आपको पहले पैराग्राफ को पढ़ना चाहिए कि मुझे क्यों लगता है कि पूरे रिसाइकिलवेरी को एनिमेट करना प्रत्येक आइटम की तुलना में बेहतर विचार है। आप प्रत्येक आइटम को एनिमेट करने का प्रयास कर सकते हैं लेकिन यह अच्छा नहीं लगेगा।
सिमोन

क्या है latestPostRecyclerview?
एंटोनियो

1
क्या आपने मेरे उत्तर के पहले पैराग्राफ को पढ़ा है जहां मैंने कारण बताया था कि आइटम विचारों को एनिमेट करना इतना अच्छा विचार क्यों नहीं है? इसके अलावा मैं सुझाए गए समाधान को आज़माने का सुझाव दूंगा और फिर आपको समस्या का एहसास होगा, वापस आकर इस समाधान का प्रयास करें।
साइमन

3

इस विधि को अपने रिसाइकलव्यू एडेप्टर में बनाएँ

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

और अंत में onBindViewHolder में कोड की इस लाइन को जोड़ें

setZoomInAnimation(holder.itemView);


2

2019 में, मैं सभी आइटम एनिमेशन को ItemAnimator में डालने का सुझाव दूंगा।

आइए पुनर्नवीनीकरण-दृश्य में एनिमेटर घोषित करने के साथ शुरू करें:

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

कस्टम एनिमेटर की घोषणा करें,

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

}

ऊपर वाले के समान गायब होने animateDisappearance, जोड़ने के लिए animateAdd, परिवर्तन animateChangeऔर चाल के लिए एक है animateMove

एक महत्वपूर्ण बिंदु सही एनीमेशन-डिस्पैचर को उनके अंदर कॉल करना होगा।


क्या आप इस ओवरराइड फ़ंक्शन का उपयोग करके कस्टम उपस्थिति एनीमेशन का एक उदाहरण प्रदान कर सकते हैं? मुझे एक उदाहरण नहीं मिल रहा है और मुझे यकीन नहीं है कि मुझे फ़ंक्शन में एनीमेशन निर्दिष्ट करना है।
मीनार

1
gist.github.com/tadfisher/120d03f8380bfa8a16bf मैंने इसे त्वरित खोज पर ऑनलाइन पाया, इससे यह पता चलता है कि ओवरलोडिंग कैसे काम करती है
दिनेश

0

बस नीचे की तरह अपने एडाप्टर का विस्तार

public class RankingAdapter extends AnimatedRecyclerView<RankingAdapter.ViewHolder> 

और onBindViewHolder में सुपर विधि जोड़ें

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

यह "बशीर अल-मोमानी" जैसे एनिमेटेड एडेप्टर बनाने का स्वचालित तरीका है

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

मुझे लगता है, इसे इस तरह से उपयोग करना बेहतर है: (RecyclerView एडॉप्टर में सिर्फ एक विधि को ओवरराइड करें)

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

    setBindAnimation(holder)
}

यदि आप आरवी में हर एनीमेशन संलग्न करना चाहते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.