Categories
Studio

Facebook Rebound with RecyclerView Items – The Best Spring Animation

If you see Facebook’s profile on Github, you’ll find quite a lot of libraries from them. One of them is Rebound. Facebook explains this library as:

Rebound spring models can be used to create animations that feel natural by introducing real world physics to your application.

To get my hands on this library, I implemented it in gradle and then blank. What do I do now? Facebook doesn’t have any Usage guides for this (documentation is there). After searching a lot on the internet, I found a solution and copied the complete code and modified as per my taste. Now my app has real-world physics-based animations.

Even swiping back and forth feels good on RecyclerView now. Let’s recreate a recyclerview with rebound animations.

Add Rebound library in Gradle.

implementation 'com.facebook.rebound:rebound:0.3.8'

Create a new class (RecyclerViewAnimator). (Facebook Rebound). You can configure friction and tension as per your needs.

public class RecyclerViewAnimator {
    /**
     * Initial delay before to show items - in ms
     */
    private static final int INIT_DELAY = 1000;

    /**
     * Initial entrance tension parameter.
     * See https://facebook.github.io/rebound/
     */
    private static final int INIT_TENSION = 250;
    /**
     * Initial entrance friction parameter.
     */
    private static final int INIT_FRICTION = 18;

    /**
     * Scroll entrance animation tension parameter.
     */
    private static final int SCROLL_TENSION = 300;
    /**
     * Scroll entrance animation friction parameter.
     */
    private static final int SCROLL_FRICTION = 30;


    private int mHeight;
    private RecyclerView mRecyclerView;
    private SpringSystem mSpringSystem;

    private boolean mFirstViewInit = true;
    private int mLastPosition = -1;
    private int mStartDelay;

    public RecyclerViewAnimator(RecyclerView recyclerView) {
        mRecyclerView = recyclerView;
        mSpringSystem = SpringSystem.create();

        // Use height of RecyclerView to slide-in items from bottom.
        mHeight = mRecyclerView.getResources().getDisplayMetrics().heightPixels;

        mStartDelay = INIT_DELAY;
    }

    public void onCreateViewHolder(View item) {
        /**
         * mFirstViewInit is used because we only want to show animation once at initialization.
         * (onCreateViewHolder can be called after if you use multiple view types).
         */
        if (mFirstViewInit) {
            slideInBottom(item, mStartDelay, INIT_TENSION, INIT_FRICTION);
            mStartDelay += 70;
        }
    }

    public void onBindViewHolder(View item, int position) {
        /**
         * After init, animate once item by item when user scroll down.
         */
        if (!mFirstViewInit && position > mLastPosition) {
            slideInBottom(item, 0, SCROLL_TENSION, SCROLL_FRICTION);
            mLastPosition = position;
        }
    }

    private void slideInBottom(final View item,
                               final int delay,
                               final int tension,
                               final int friction) {
        // Move item far outside the RecyclerView
        item.setTranslationY(mHeight);

        Runnable startAnimation = new Runnable() {
            @Override
            public void run() {
                SpringConfig config = new SpringConfig(tension, friction);
                Spring spring = mSpringSystem.createSpring();
                spring.setSpringConfig(config);
                spring.addListener(new SimpleSpringListener() {
                    @Override
                    public void onSpringUpdate(Spring spring) {
                        /**
                         * Decrease translationY until 0.
                         */
                        float val = (float) (mHeight - spring.getCurrentValue());
                        item.setTranslationY(val);
                    }

                    @Override
                    public void onSpringEndStateChange(Spring spring) {
                        mFirstViewInit = false;
                    }
                });

                // Set the spring in motion; moving from 0 to height
                spring.setEndValue(mHeight);
            }
        };

        mRecyclerView.postDelayed(startAnimation, delay);
    }
}

Go to RecyclerView Adapter class, init RecyclerViewAnimator class.

private class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewKaHolder>
{
    private ArrayList<String> datasets;
    private Context context;
    private RecyclerViewAnimator mAnimator;
...

Initialise it in the constructor:

MyAdapter(ArrayList<String> datasets, Context context)
{
    mAnimator = new RecyclerViewAnimator(recyclerView);
    this.datasets = datasets;
    this.context = context;
}

For first item animation, In onCreateViewHolder

@NonNull
@Override
public ViewKaHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
{
    FrameLayout relativeLayout = (FrameLayout) LayoutInflater.from(getApplicationContext()).inflate(R.layout.recyler5_single_layout, parent, false);
    mAnimator.onCreateViewHolder(relativeLayout);
    return new ViewKaHolder(relativeLayout);
}

onBindViewHolder

@Override
public void onBindViewHolder(@NonNull ViewKaHolder holder, int position) {
    holder.textView.setText(datasets.get(position));
    /**
     * Item's entrance animations during scroll are performed here.
     */
    mAnimator.onBindViewHolder(holder.itemView, position);
}

And that’s it. You have successfully implemented Facebook Rebound for RecyclerView.

Changes you can do with Facebook Rebound RecyclerView Animator

If you copied the code as it is, then it will create delayed and clumsy animations. You should modify these constant fields:

  1. INIT_DELAY: By default, the author set it to 1000 which is 1 second and that’s a long time. Reduce it to 50 or 100.
  2. INIT_TENSION and INIT_FRICTION: Init, as the name suggests, is for the first time only. For a smooth experience, Set INIT_TENSION same as SCROLL_TENSION and INIT_FRICTION same as SCROLL_FRICTION. And play with the values.

I have used this in my new app – Scholar (Q&A). Check out that app on Play Store.

Leave a Reply

Your email address will not be published. Required fields are marked *