Skip to content

Instantly share code, notes, and snippets.

@JSpiner
Created August 9, 2017 07:14
Show Gist options
  • Save JSpiner/69c203b13629927d7d13c8987969f78e to your computer and use it in GitHub Desktop.
Save JSpiner/69c203b13629927d7d13c8987969f78e to your computer and use it in GitHub Desktop.
Smooth Scroll AppBarLayout FlingBehavior
public final class FlingBehavior extends AppBarLayout.Behavior {
private boolean isPositive;
private float mFlingFriction = ViewConfiguration.getScrollFriction();
private float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
private final float INFLEXION = 0.35f;
private float mPhysicalCoeff;
//https://stackoverflow.com/questions/30923889/flinging-with-recyclerview-appbarlayout
//I made java version by referring to julian's kotlin code and subtract reflection.
//https://stackoverflow.com/a/43594597/7957535
public FlingBehavior(){
init();
}
public FlingBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init(){
final float ppi = BaseApplication.getInstance().getResources().getDisplayMetrics().density * 160.0f;
mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2)
* 39.37f // inch/meter
* ppi
* 0.84f; // look and feel tuning
}
@Override
public boolean onNestedFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY, boolean consumed) {
if (velocityY > 0 && !isPositive || velocityY < 0 && isPositive) {
velocityY = velocityY * -1;
}
if (target instanceof RecyclerView && velocityY < 0) {
RecyclerView recyclerView = (RecyclerView) target;
double distance = getFlingDistance((int) velocityY);
if (distance < recyclerView.computeVerticalScrollOffset()) {
consumed = true;
} else {
consumed = false;
}
}
return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed) {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
isPositive = dy > 0;
}
public double getFlingDistance(int velocity){
final double l = getSplineDeceleration(velocity);
final double decelMinusOne = DECELERATION_RATE - 1.0;
return mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l);
}
private double getSplineDeceleration(int velocity) {
return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment