Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit efbd7e3b authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Improve logic when flinging up.

Makes sure that we don't accelerate even more if the movement is
already fast enough. Around 3000dp/s, we switch to a linear curve.

Change-Id: I9a1cdb1a0a65ed7a8ddf00683c08e83c13bf20f7
parent 1d480695
Loading
Loading
Loading
Loading
+26 −5
Original line number Diff line number Diff line
@@ -28,33 +28,35 @@ import android.view.animation.PathInterpolator;
public class FlingAnimationUtils {

    private static final float LINEAR_OUT_SLOW_IN_X2 = 0.35f;
    private static final float LINEAR_OUT_FASTER_IN_Y2 = 0.7f;
    private static final float LINEAR_OUT_FASTER_IN_Y2_MIN = 0.7f;
    private static final float LINEAR_OUT_FASTER_IN_Y2_MAX = 1f;
    private static final float MIN_VELOCITY_DP_PER_SECOND = 250;
    private static final float HIGH_VELOCITY_DP_PER_SECOND = 3000;

    /**
     * Crazy math. http://en.wikipedia.org/wiki/B%C3%A9zier_curve
     */
    private static final float LINEAR_OUT_SLOW_IN_START_GRADIENT = 1.0f / LINEAR_OUT_SLOW_IN_X2;
    private static final float LINEAR_OUT_FASTER_IN_START_GRADIENT = LINEAR_OUT_FASTER_IN_Y2;

    private Interpolator mLinearOutSlowIn;
    private Interpolator mFastOutSlowIn;
    private Interpolator mFastOutLinearIn;
    private Interpolator mLinearOutFasterIn;

    private float mMinVelocityPxPerSecond;
    private float mMaxLengthSeconds;
    private float mHighVelocityPxPerSecond;

    public FlingAnimationUtils(Context ctx, float maxLengthSeconds) {
        mMaxLengthSeconds = maxLengthSeconds;
        mLinearOutSlowIn = new PathInterpolator(0, 0, LINEAR_OUT_SLOW_IN_X2, 1);
        mLinearOutFasterIn = new PathInterpolator(0, 0, 1, LINEAR_OUT_FASTER_IN_Y2);
        mFastOutSlowIn
                = AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_slow_in);
        mFastOutLinearIn
                = AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_linear_in);
        mMinVelocityPxPerSecond
                = MIN_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
        mHighVelocityPxPerSecond
                = HIGH_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
    }

    /**
@@ -126,7 +128,12 @@ public class FlingAnimationUtils {
                * Math.pow(Math.abs(endValue - currValue) / maxDistance, 0.5f));
        float diff = Math.abs(endValue - currValue);
        float velAbs = Math.abs(velocity);
        float durationSeconds = LINEAR_OUT_FASTER_IN_START_GRADIENT * diff / velAbs;
        float y2 = calculateLinearOutFasterInY2(velAbs);

        // The gradient at the start of the curve is just y2.
        float startGradient = y2;
        Interpolator mLinearOutFasterIn = new PathInterpolator(0, 0, 1, y2);
        float durationSeconds = startGradient * diff / velAbs;
        if (durationSeconds <= maxLengthSeconds) {
            animator.setInterpolator(mLinearOutFasterIn);
        } else if (velAbs >= mMinVelocityPxPerSecond) {
@@ -148,6 +155,20 @@ public class FlingAnimationUtils {
        animator.setDuration((long) (durationSeconds * 1000));
    }

    /**
     * Calculates the y2 control point for a linear-out-faster-in path interpolator depending on the
     * velocity. The faster the velocity, the more "linear" the interpolator gets.
     *
     * @param velocity the velocity of the gesture.
     * @return the y2 control point for a cubic bezier path interpolator
     */
    private float calculateLinearOutFasterInY2(float velocity) {
        float t = (velocity - mMinVelocityPxPerSecond)
                / (mHighVelocityPxPerSecond - mMinVelocityPxPerSecond);
        t = Math.max(0, Math.min(1, t));
        return (1 - t) * LINEAR_OUT_FASTER_IN_Y2_MIN + t * LINEAR_OUT_FASTER_IN_Y2_MAX;
    }

    /**
     * @return the minimum velocity a gesture needs to have to be considered a fling
     */