18

What I'm trying to accomplish

I want to make items in a linear vertical RecyclerView appear in order. I want the 1st item to appear, then the 2nd, then the 3rd and so on. Here is an example of the type of animation I'm trying to accomplish.

animation example


What I've tried

I have tried the methods provided in this question: How to animate RecyclerView items when they appear

However, this is not quite what I'm trying to accomplish. This causes all the items in the RecyclerView to appear at once, rather than one at a time.


My code

public class ParentCommentsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private int lastPosition = -1;

    //constructor and other code not shown...

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
        switch (viewHolder.getItemViewType()) {
            case OP:
                OPViewHolder ovh = (OPViewHolder) viewHolder;
                configureOPViewHolder(ovh, position);
                setAnimation(ovh.getContainer(), position);
                break;
            case COMMENT:
                CommentViewHolder cvh = (CommentViewHolder) viewHolder;
                configureCommentViewHolder(cvh, position);
                setAnimation(cvh.getContainer(), position);
                break;
            default:
                RecyclerViewSimpleTextViewHolder vh = (RecyclerViewSimpleTextViewHolder) viewHolder;
                configureDefaultViewHolder(vh, position);
                break;
        }

    }

    @Override
    public void onViewDetachedFromWindow(final RecyclerView.ViewHolder viewHolder)
    {

        switch (viewHolder.getItemViewType()) {
            case OP:
                ((OPViewHolder)viewHolder).clearAnimation();
                break;
            case COMMENT:
                ((CommentViewHolder)viewHolder).clearAnimation();
                break;
            default:
                break;
        }
    }

    private void configureDefaultViewHolder(RecyclerViewSimpleTextViewHolder vh, int position) {
        //code...
    }

    private void configureOPViewHolder(OPViewHolder vh1, int position) {
        //code...
    }

    private void configureCommentViewHolder(CommentViewHolder vh2, int position) {
        //code...
    }

    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, R.anim.fade_in);
            viewToAnimate.startAnimation(animation);
            lastPosition = position;
        }
    }

}
Community
  • 1
  • 1
Vishnu M.
  • 971
  • 1
  • 10
  • 18
  • Have you considered an OSS project like https://github.com/wasabeef/recyclerview-animators ? – Sebastian Roth Aug 12 '16 at 03:46
  • @SebastianRoth I did run across that project while I was researching. That project seems to have many animations but I already have my own animation that I want to use. My problem is that I want the recyclerview items to animate in order when the activity is opened initially. So when the activity is opened I want item one to animate in, then item 2 and then item 3 and so on. – Vishnu M. Aug 12 '16 at 03:53

4 Answers4

21

After you call setAdapter you can run following:

recyclerView.getViewTreeObserver().addOnPreDrawListener(
        new ViewTreeObserver.OnPreDrawListener() {

            @Override
            public boolean onPreDraw() {
                recyclerView.getViewTreeObserver().removeOnPreDrawListener(this);

                for (int i = 0; i < recyclerView.getChildCount(); i++) {
                    View v = recyclerView.getChildAt(i);
                    v.setAlpha(0.0f);
                    v.animate().alpha(1.0f)
                            .setDuration(300)
                            .setStartDelay(i * 50)
                            .start();
                }

                return true;
            }
        });

Example shows simple alpha animation, but you can run what you want in the loop and adjust interpolator, duration and start delay.

Niko
  • 8,093
  • 5
  • 49
  • 85
  • This worked great, I simply replaced the animation with my own. Looks like the key is to add the setStartDelay option and have the delay change relative to the item position. Thank you very much, Niko. – Vishnu M. Aug 12 '16 at 04:50
  • Is there a way to remove an OnPreDrawListener? Let's say I want to use a different animation later on, how would I do that? I tried to add a different method that was the same as here but with a different animation but it seems like it just adds that animation on top of the current animation. – Vishnu M. Aug 12 '16 at 05:55
  • This is one time trigger after you have called setAdapter, removeOnPreDrawListener is called in onPreDraw method. When you want different animation later are you calling setAdapter or adding/removing items with existing adapter? – Niko Aug 12 '16 at 05:58
  • I am adding and removing items using the existing adapter. This causes the items in the RecyclerView currently to move down with the delay introduced in the PreDrawListener. – Vishnu M. Aug 12 '16 at 14:06
  • Can you post a new question about it with the code you are trying – Niko Aug 13 '16 at 04:03
  • Thank you, I've posted a new question [here](http://stackoverflow.com/questions/38935878/odd-behavior-with-recyclerview-animations-using-onpredraw) – Vishnu M. Aug 13 '16 at 18:45
  • I am using the code there for initial animation and it works okay. You might be calling it too much or in wrong place. It is one trigger code called after you set adapter. When onPreDraw triggers once the listener is removed in the code. – Niko Aug 14 '16 at 03:43
11

I have decided to use a different approach from what Niko suggested earlier. His method works great and is very easy, but it was causing some buggy animations when adding and removing items (as can be seen here).

So I decided to try a different approach and use a layout animation controller. Here's the code I used to achieve the same result.

public void initialRVAnimation() {

    AnimationSet set = new AnimationSet(true);

    // Fade in animation
    Animation fadeIn = new AlphaAnimation(0.0f, 1.0f);
    fadeIn.setDuration(400);
    fadeIn.setFillAfter(true);
    set.addAnimation(fadeIn);

    // Slide up animation from bottom of screen
    Animation slideUp = new TranslateAnimation(0, 0, Utils.getScreenHeight(this), 0);
    slideUp.setInterpolator(new DecelerateInterpolator(4.f));
    slideUp.setDuration(400);
    set.addAnimation(slideUp);

    // Set up the animation controller              (second parameter is the delay)
    LayoutAnimationController controller = new LayoutAnimationController(set, 0.2f);
    rv.setLayoutAnimation(controller);

    // Set the adapter
    adapter = new ItemAdapter(data, this);
    recyclerView.setAdapter(adapter);
}
Vishnu M.
  • 971
  • 1
  • 10
  • 18
  • I am implementing the same thing but when i apply your answer or the accepted answer it doesnt work for me. for initial item can not see the animation. all appear at same time. Can you suggest me anything – djk Jul 07 '17 at 18:32
  • 1
    The part which controls the delay is the second parameter of the LayoutAnimationController. Make sure you are setting the layout animation by doing `recyclerView.setLayoutAnimation(controller)` – Vishnu M. Jul 09 '17 at 02:23
  • it works for me but I was not able to make it work when removing items. Did you do that? – Juan Saravia Aug 23 '18 at 18:09
1

Easy way is set in xml in your RecyclerView tag (or in code like above comment)

android:layoutAnimation="@anim/slide_left_in_layout_anim"

slide_left_in_layout_anim.xml

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

Note: this animation only excuted when first time load data, if you want add animation when add/remove/move an item, take a look at ItemAnimator and i think this post will help you know something that helpful

1

In addition to @Niko's answer for Kotlin try this solution.

call this after setting adapter

rvTop!!.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
                        override fun onPreDraw(): Boolean {
                            rvTop!!.getViewTreeObserver().removeOnPreDrawListener(this);

                            for (i in 0 until rvTop!!.getChildCount()) {
                                var v = rvTop!!.getChildAt(i);
                                v.setAlpha(0.0f);
                                v.animate().alpha(1.0f)
                                        .setDuration(300)
                                        .setStartDelay((i * 50).toLong())
                                        .start();
                            }

                            return true
                        }


                    })
Quick learner
  • 10,632
  • 4
  • 45
  • 55
  • Hello Quick Learner, can you tell me what type of the variable "v" do you get? Thank you – Lilia Mar 15 '20 at 12:15