Add IOS-like overscroll animation to your scrolling views using SpringAnimation.
Currently includes BouncyRecyclerView and BouncyNestedScrollView.
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'
}
NestedScrollView with bouncy overscroll effect, currently only supports vertical scrolling.
Achieved by overriding the default EdgeEffect
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.
bouncy_scroll_view.setBindSpringToParent(true);
// this will bind the spring animations to parent instead of self
BouncyRecyclerView adds overscroll effect to RecyclerView and supports drag & drop and swiping gestures
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));
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);
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.
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 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
Factor Launcher - A Windows Phone inspired launcher with some modern touch
Mutify - Automatically turn on do-not-disturb based on where you are