valkriaine / Bouncy

RecyclerView and NestedScrollView with physics-based bouncy overscroll effect
Apache License 2.0
198 stars 18 forks source link
android android-library dynamic-animation edge-effects factor-launcher nestedscrollview overscroll recyclerview spring-animation

Bouncy

Android Arsenal

Add IOS-like overscroll animation to your scrolling views using SpringAnimation.

Currently includes BouncyRecyclerView and BouncyNestedScrollView.

Add Bouncy to your project

Gradle

Add it in your root build.gradle at the end of repositories:

 allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }

In your app module build.gradle, add dependency for recyclerview and bouncy:

   dependencies {
        implementation 'androidx.recyclerview:recyclerview:1.2.1'
        implementation 'com.github.valkriaine:Bouncy:2.3'
   }

BouncyNestedScrollView

NestedScrollView with bouncy overscroll effect, currently only supports vertical scrolling.

Achieved by overriding the default EdgeEffect

Usage:

Use as normal NestedScrollView. Place it in your layout:

<com.factor.bouncy.BouncyNestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:fling_animation_size=".7"
        app:overscroll_animation_size=".7">

    <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            ...
            ...
            ...

    </LinearLayout>

</com.factor.bouncy.BouncyNestedScrollView>

fling_animation_size specifies the magnitude of overscroll effect for fling, default is 0.5 if no value is given.

overscroll_animation_size specifies the magnitude of overscroll effect for drag, default is 0.5 if no value is given.

Strongly suggest to keep both values lower than 5.

It is now possible to bind bouncy animation to parent instead of BouncyNestedScrollView

bouncy_scroll_view.setBindSpringToParent(true);

// this will bind the spring animations to parent instead of self

BouncyRecyclerView

BouncyRecyclerView adds overscroll effect to RecyclerView and supports drag & drop and swiping gestures

Usage:

Use as normal RecyclerView. Place it in your layout:

<com.factor.bouncy.BouncyRecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:recyclerview_fling_animation_size=".7"
        app:recyclerview_overscroll_animation_size=".7"
        app:recyclerview_damping_ratio="DAMPING_RATIO_LOW_BOUNCY"
        app:recyclerview_stiffness="STIFFNESS_MEDIUM"
        app:allow_drag_reorder="true"
        app:allow_item_swipe="false"/>

set up layout manager and adapter. Theoratically supports any LayoutManager:

   recycler_view.setAdapter(myAdapter);
   recycler_view.setLayoutManager(new LinearLayoutManager(context));
   //recycler_view.setLayoutManager(new GridLayoutManager(context, 3));

Orientation

When you set the LayoutManager, BouncyRecyclerView will automatically detect the orientation of the layout.

   recycler_view.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));

If the bounce animation is incorrect, you can also manually set the animation orientation:

   recycler_view.setOrientation(LinearLayoutManager.VERTICAL);

Customization

recyclerview_fling_animation_size specifies the magnitude of overscroll effect for fling, default is 0.5 if no value is given

recyclerview_overscroll_animation_size specifies the magnitude of overscroll effect for drag, default is 0.5 if no value is given

allow_drag_reorder and allow_item_swipe are set to false by default. If you would like to enable these features, simply set them to true.

Spring customization

recyclerview_damping_ratio and recyclerview_stiffness please refer to damping ratio and stiffness

Set in code:

   recycler_view.setFlingAnimationSize(0.3f);
   recycler_view.setOverscrollAnimationSize(0.3f);
   recycler_view.setDampingRatio(Bouncy.DAMPING_RATIO_HIGH_BOUNCY);
   recycler_view.setStiffness(Bouncy.STIFFNESS_HIGH);

Drag & drop

Drag & drop does not work out of the box.

For drag & drop or swipe gestures to work, make your adapter extend BouncyRecyclerView.Adapter. (If your adapter does not extend BouncyRecyclerView.Adapter, BouncyRecyclerView will simply disable the gestures)

public class MyAdapter extends BouncyRecyclerView.Adapter
{
    private final ArrayList<MyData> dataSet;

    public MyAdapter(ArrayList<MyData> dataSet)
    {
        this.dataSet = dataSet;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
    {
        MyViewHolder h = (MyViewHolder) holder;
        h.getTextView().setText(dataSet.get(position).getData());
    }

    @Override
    public int getItemCount()
    {
        return dataSet.size();
    }

    @Override
    public void onItemMoved(int fromPosition, int toPosition)
    {
        //*****must override to save changes 
        //called repeatedly when item is dragged (reordered)

        //example of handling reorder
        MyData item = dataSet.remove(fromPosition);
        dataSet.add(toPosition, item);
        notifyItemMoved(fromPosition, toPosition);
    }

    @Override
    public void onItemSwipedToStart(RecyclerView.ViewHolder viewHolder, int position)
    {
        //item swiped left
    }

    @Override
    public void onItemSwipedToEnd(RecyclerView.ViewHolder viewHolder, int position)
    {
        //item swiped right
    }

    @Override
    public void onItemSelected(RecyclerView.ViewHolder viewHolder)
    {
        //item long pressed (selected)
    }

    @Override
    public void onItemReleased(RecyclerView.ViewHolder viewHolder)
    {
        //item released (unselected)
    }
}

Also refer to the Kotlin example

My other projects

Factor Launcher - A Windows Phone inspired launcher with some modern touch

Mutify - Automatically turn on do-not-disturb based on where you are