Rewrite long swipe resistance ("pullback") logic

- Rename "pullback" to "resistance" to reduce confusion.
- Remove mDragLengthFactorStartPullback & mDragLengthFactorMaxPullback
- Add AnimatorControllerWithResistance, which has 2 controllers, one
  for the normal shift to overview, then one to apply the resistance
  when swiping beyond that.
- Don't hack animator interpolators/progress; insteaad, allow progress
  to go > 1 (which will run the separate resistance animator).
- Don't start launcher controller separately from window controller;
  instead, both are controlled by mCurrentShift in updateFinalShift().
- The resistance animation logic is shared by both the active window
  and launcher (RecentsView).

Bug: 149934536
Change-Id: Ib0f9da18e10cc9ddf1a2f82ed767f237c89d3a41
Merged-In: Ib0f9da18e10cc9ddf1a2f82ed767f237c89d3a41
This commit is contained in:
Tony Wickham
2020-06-25 15:51:33 -07:00
parent d354443535
commit 354a436f4e
10 changed files with 198 additions and 83 deletions
@@ -79,8 +79,8 @@ final class AppToOverviewAnimationProvider<T extends StatefulActivity<?>> extend
BaseActivityInterface.AnimationFactory factory = mActivityInterface.prepareRecentsUI(
mDeviceState,
wasVisible, (controller) -> {
controller.dispatchOnStart();
controller.getAnimationPlayer().end();
controller.getNormalController().dispatchOnStart();
controller.getNormalController().getAnimationPlayer().end();
});
factory.createActivityInterface(RECENTS_LAUNCH_DURATION);
factory.setRecentsAttachedToAppWindow(true, false);
@@ -365,8 +365,7 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
*/
protected void applyWindowTransform() {
if (mWindowTransitionController != null) {
float progress = mCurrentShift.value / mDragLengthFactor;
mWindowTransitionController.setPlayFraction(progress);
mWindowTransitionController.setProgress(mCurrentShift.value, mDragLengthFactor);
}
if (mRecentsAnimationTargets != null) {
if (mRecentsViewScrollLinked) {
@@ -21,7 +21,6 @@ import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_GESTURE;
@@ -45,7 +44,6 @@ import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHO
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.ActivityManager;
@@ -67,7 +65,6 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.UserEventDispatcher;
@@ -80,6 +77,7 @@ import com.android.quickstep.BaseActivityInterface.AnimationFactory;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.ShelfPeekAnim;
import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
@@ -181,8 +179,7 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
private ThumbnailData mTaskSnapshot;
// Used to control launcher components throughout the swipe gesture.
private AnimatorPlaybackController mLauncherTransitionController;
private boolean mHasLauncherTransitionControllerStarted;
private AnimatorControllerWithResistance mLauncherTransitionController;
private AnimationFactory mAnimationFactory = (t) -> { };
@@ -528,11 +525,11 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
/**
* We don't want to change mLauncherTransitionController if mGestureState.getEndTarget() == HOME
* (it has its own animation) or if we're already animating the current controller.
* (it has its own animation).
* @return Whether we can create the launcher controller or update its progress.
*/
private boolean canCreateNewOrUpdateExistingLauncherTransitionController() {
return mGestureState.getEndTarget() != HOME && !mHasLauncherTransitionControllerStarted;
return mGestureState.getEndTarget() != HOME;
}
@Override
@@ -542,10 +539,9 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
return result;
}
private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) {
private void onAnimatorPlaybackControllerCreated(AnimatorControllerWithResistance anim) {
mLauncherTransitionController = anim;
mLauncherTransitionController.dispatchSetInterpolator(t -> t * mDragLengthFactor);
mLauncherTransitionController.dispatchOnStart();
mLauncherTransitionController.getNormalController().dispatchOnStart();
updateLauncherTransitionProgress();
}
@@ -582,10 +578,7 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|| !canCreateNewOrUpdateExistingLauncherTransitionController()) {
return;
}
// Normalize the progress to 0 to 1, as the animation controller will clamp it to that
// anyway. The controller mimics the drag length factor by applying it to its interpolators.
float progress = mCurrentShift.value / mDragLengthFactor;
mLauncherTransitionController.setPlayFraction(progress);
mLauncherTransitionController.setProgress(mCurrentShift.value, mDragLengthFactor);
}
/**
@@ -1028,31 +1021,6 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
windowAnim.start();
mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
}
// Always play the entire launcher animation when going home, since it is separate from
// the animation that has been controlled thus far.
if (mGestureState.getEndTarget() == HOME) {
start = 0;
}
// We want to use the same interpolator as the window, but need to adjust it to
// interpolate over the remaining progress (end - start).
TimeInterpolator adjustedInterpolator = Interpolators.mapToProgress(
interpolator, start, end);
if (mLauncherTransitionController == null) {
return;
}
if (start == end || duration <= 0) {
mLauncherTransitionController.dispatchSetInterpolator(t -> end);
} else {
mLauncherTransitionController.dispatchSetInterpolator(adjustedInterpolator);
}
mLauncherTransitionController.getAnimationPlayer().setDuration(Math.max(0, duration));
if (UNSTABLE_SPRINGS.get()) {
mLauncherTransitionController.dispatchOnStart();
}
mLauncherTransitionController.getAnimationPlayer().start();
mHasLauncherTransitionControllerStarted = true;
}
private void computeRecentsScrollIfInvisible() {
@@ -1173,10 +1141,6 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
private void cancelCurrentAnimation() {
mCanceled = true;
mCurrentShift.cancelAnimation();
if (mLauncherTransitionController != null && mLauncherTransitionController
.getAnimationPlayer().isStarted()) {
mLauncherTransitionController.getAnimationPlayer().cancel();
}
}
private void invalidateHandler() {
@@ -1202,7 +1166,10 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
private void endLauncherTransitionController() {
setShelfState(ShelfAnimState.CANCEL, LINEAR, 0);
if (mLauncherTransitionController != null) {
mLauncherTransitionController.getAnimationPlayer().end();
// End the animation, but stay at the same visual progress.
mLauncherTransitionController.getNormalController().dispatchSetInterpolator(
t -> Utilities.boundToRange(mCurrentShift.value, 0, 1));
mLauncherTransitionController.getNormalController().getAnimationPlayer().end();
mLauncherTransitionController = null;
}
}
@@ -27,11 +27,11 @@ import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.fallback.RecentsState;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -84,7 +84,7 @@ public final class FallbackActivityInterface extends
/** 6 */
@Override
public AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState,
boolean activityVisible, Consumer<AnimatorPlaybackController> callback) {
boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback) {
DefaultAnimationFactory factory = new DefaultAnimationFactory(callback);
factory.initUI();
return factory;
@@ -39,7 +39,6 @@ import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.appprediction.PredictionUiStateManager;
import com.android.launcher3.statehandlers.DepthController;
@@ -50,6 +49,7 @@ import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
import com.android.quickstep.views.RecentsView;
@@ -119,7 +119,7 @@ public final class LauncherActivityInterface extends
@Override
public AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState,
boolean activityVisible, Consumer<AnimatorPlaybackController> callback) {
boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback) {
notifyRecentsOfOrientation(deviceState.getRotationTouchHelper());
DefaultAnimationFactory factory = new DefaultAnimationFactory(callback) {
@Override
@@ -16,7 +16,7 @@
package com.android.quickstep;
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import android.animation.Animator;
import android.content.Context;
@@ -24,7 +24,6 @@ import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.Rect;
import android.graphics.RectF;
import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
@@ -35,6 +34,7 @@ import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
@@ -45,7 +45,6 @@ import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.
public abstract class SwipeUpAnimationLogic {
protected static final Rect TEMP_RECT = new Rect();
private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL;
protected DeviceProfile mDp;
@@ -66,12 +65,8 @@ public abstract class SwipeUpAnimationLogic {
protected int mTransitionDragLength;
// How much further we can drag past recents, as a factor of mTransitionDragLength.
protected float mDragLengthFactor = 1;
// Start resisting when swiping past this factor of mTransitionDragLength.
private float mDragLengthFactorStartPullback = 1f;
// This is how far down we can scale down, where 0f is full screen and 1f is recents.
private float mDragLengthFactorMaxPullback = 1f;
protected AnimatorPlaybackController mWindowTransitionController;
protected AnimatorControllerWithResistance mWindowTransitionController;
public SwipeUpAnimationLogic(Context context, RecentsAnimationDeviceState deviceState,
GestureState gestureState, TransformParams transformParams) {
@@ -97,19 +92,16 @@ public abstract class SwipeUpAnimationLogic {
if (mDeviceState.isFullyGesturalNavMode()) {
// We can drag all the way to the top of the screen.
mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;
float startScale = mTaskViewSimulator.getFullScreenScale();
// Start pulling back when RecentsView scale is 0.75f, and let it go down to 0.5f.
mDragLengthFactorStartPullback = (0.75f - startScale) / (1 - startScale);
mDragLengthFactorMaxPullback = (0.5f - startScale) / (1 - startScale);
} else {
mDragLengthFactor = 1;
mDragLengthFactorStartPullback = mDragLengthFactorMaxPullback = 1;
mDragLengthFactor = 1 + AnimatorControllerWithResistance.TWO_BUTTON_EXTRA_DRAG_FACTOR;
}
PendingAnimation pa = new PendingAnimation(mTransitionDragLength * 2);
mTaskViewSimulator.addAppToOverviewAnim(pa, t -> t * mDragLengthFactor);
mWindowTransitionController = pa.createPlaybackController();
mTaskViewSimulator.addAppToOverviewAnim(pa, LINEAR);
AnimatorPlaybackController normalController = pa.createPlaybackController();
mWindowTransitionController = AnimatorControllerWithResistance.createForRecents(
normalController, mContext, mTaskViewSimulator.getOrientationState(),
mDp, mTaskViewSimulator.recentsViewScale, AnimatedFloat.VALUE);
}
@UiThread
@@ -122,13 +114,6 @@ public abstract class SwipeUpAnimationLogic {
} else {
float translation = Math.max(displacement, 0);
shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
if (shift > mDragLengthFactorStartPullback) {
float pullbackProgress = Utilities.getProgress(shift,
mDragLengthFactorStartPullback, mDragLengthFactor);
pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress);
shift = mDragLengthFactorStartPullback + pullbackProgress
* (mDragLengthFactorMaxPullback - mDragLengthFactorStartPullback);
}
}
mCurrentShift.updateValue(shift);
@@ -183,7 +168,7 @@ public abstract class SwipeUpAnimationLogic {
HomeAnimationFactory homeAnimationFactory) {
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
mWindowTransitionController.setPlayFraction(startProgress / mDragLengthFactor);
mCurrentShift.updateValue(startProgress);
mTaskViewSimulator.apply(mTransformParams.setProgress(startProgress));
RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect());
@@ -52,6 +52,7 @@ import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.WindowBounds;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.ShelfPeekAnim;
import com.android.quickstep.util.SplitScreenBounds;
import com.android.quickstep.views.RecentsView;
@@ -106,7 +107,7 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
public abstract void onAssistantVisibilityChanged(float visibility);
public abstract AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState,
boolean activityVisible, Consumer<AnimatorPlaybackController> callback);
boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback);
public abstract ActivityInitListener createActivityInitListener(
Predicate<Boolean> onInitListener);
@@ -319,11 +320,11 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
protected final ACTIVITY_TYPE mActivity;
private final STATE_TYPE mStartState;
private final Consumer<AnimatorPlaybackController> mCallback;
private final Consumer<AnimatorControllerWithResistance> mCallback;
private boolean mIsAttachedToWindow;
DefaultAnimationFactory(Consumer<AnimatorPlaybackController> callback) {
DefaultAnimationFactory(Consumer<AnimatorControllerWithResistance> callback) {
mCallback = callback;
mActivity = getCreatedActivity();
@@ -351,7 +352,13 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
controller.setEndAction(() -> mActivity.getStateManager().goToState(
controller.getInterpolatedProgress() > 0.5 ? mOverviewState : mBackgroundState,
false));
mCallback.accept(controller);
RecentsView recentsView = mActivity.getOverviewPanel();
AnimatorControllerWithResistance controllerWithResistance =
AnimatorControllerWithResistance.createForRecents(controller, mActivity,
recentsView.getPagedViewOrientedState(), mActivity.getDeviceProfile(),
recentsView, RECENTS_SCALE_PROPERTY);
mCallback.accept(controllerWithResistance);
// Creating the activity controller animation sometimes reapplies the launcher state
// (because we set the animation as the current state animation), so we reapply the
@@ -184,8 +184,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
@Override
public void updateFinalShift() {
float progress = mCurrentShift.value / mDragLengthFactor;
mWindowTransitionController.setPlayFraction(progress);
mWindowTransitionController.setProgress(mCurrentShift.value, mDragLengthFactor);
mTaskViewSimulator.apply(mTransformParams);
}
@@ -0,0 +1,157 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.util;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
import android.animation.TimeInterpolator;
import android.content.Context;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.FloatProperty;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.SysUINavigationMode;
/**
* Controls an animation that can go beyond progress = 1, at which point resistance should be
* applied. Internally, this is a wrapper around 2 {@link AnimatorPlaybackController}s, one that
* runs from progress 0 to 1 like normal, then one that seamlessly continues that animation but
* starts applying resistance as well.
*/
public class AnimatorControllerWithResistance {
/**
* How much farther we can drag past overview in 2-button mode, as a factor of the distance
* it takes to drag from an app to overview.
*/
public static final float TWO_BUTTON_EXTRA_DRAG_FACTOR = 0.25f;
/**
* Start slowing down the rate of scaling down when recents view is smaller than this scale.
*/
private static final float RECENTS_SCALE_START_RESIST = 0.75f;
/**
* Recents view will reach this scale at the very end of the drag.
*/
private static final float RECENTS_SCALE_MAX_RESIST = 0.5f;
private static final TimeInterpolator RECENTS_SCALE_RESIST_INTERPOLATOR = DEACCEL;
private final AnimatorPlaybackController mNormalController;
private final AnimatorPlaybackController mResistanceController;
// Initialize to -1 so the first 0 gets applied.
private float mLastNormalProgress = -1;
private float mLastResistProgress;
public AnimatorControllerWithResistance(AnimatorPlaybackController normalController,
AnimatorPlaybackController resistanceController) {
mNormalController = normalController;
mResistanceController = resistanceController;
}
public AnimatorPlaybackController getNormalController() {
return mNormalController;
}
/**
* Applies the current progress of the animation.
* @param progress From 0 to maxProgress, where 1 is the target we are animating towards.
* @param maxProgress > 1, this is where the resistance will be applied.
*/
public void setProgress(float progress, float maxProgress) {
float normalProgress = Utilities.boundToRange(progress, 0, 1);
if (normalProgress != mLastNormalProgress) {
mLastNormalProgress = normalProgress;
mNormalController.setPlayFraction(normalProgress);
}
if (maxProgress <= 1) {
return;
}
float resistProgress = progress <= 1 ? 0 : Utilities.getProgress(progress, 1, maxProgress);
if (resistProgress != mLastResistProgress) {
mLastResistProgress = resistProgress;
mResistanceController.setPlayFraction(resistProgress);
}
}
/**
* Applies resistance to recents when swiping up past its target position.
* @param normalController The controller to run from 0 to 1 before this resistance applies.
* @param context Used to compute start and end values.
* @param recentsOrientedState Used to compute start and end values.
* @param dp Used to compute start and end values.
* @param scaleTarget The target for the scaleProperty.
* @param scaleProperty Animate the value to change the scale of the window/recents view.
*/
public static <SCALE> AnimatorControllerWithResistance createForRecents(
AnimatorPlaybackController normalController, Context context,
RecentsOrientedState recentsOrientedState, DeviceProfile dp, SCALE scaleTarget,
FloatProperty<SCALE> scaleProperty) {
Rect startRect = new Rect();
LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, startRect,
recentsOrientedState.getOrientationHandler());
long distanceToCover = startRect.bottom;
boolean isTwoButtonMode = SysUINavigationMode.getMode(context) == TWO_BUTTONS;
if (isTwoButtonMode) {
// We can only drag a small distance past overview, not to the top of the screen.
distanceToCover = (long)
((dp.heightPx - startRect.bottom) * TWO_BUTTON_EXTRA_DRAG_FACTOR);
}
PendingAnimation resistAnim = new PendingAnimation(distanceToCover * 2);
PointF pivot = new PointF();
float fullscreenScale = recentsOrientedState.getFullScreenScaleAndPivot(
startRect, dp, pivot);
float startScale = 1;
float prevScaleRate = (fullscreenScale - startScale) / (dp.heightPx - startRect.bottom);
// This is what the scale would be at the end of the drag if we didn't apply resistance.
float endScale = startScale - prevScaleRate * distanceToCover;
final TimeInterpolator scaleInterpolator;
if (isTwoButtonMode) {
// We are bounded by the distance of the drag, so we don't need to apply resistance.
scaleInterpolator = LINEAR;
} else {
// Create an interpolator that resists the scale so the scale doesn't get smaller than
// RECENTS_SCALE_MAX_RESIST.
float startResist = Utilities.getProgress(RECENTS_SCALE_START_RESIST, startScale,
endScale);
float maxResist = Utilities.getProgress(RECENTS_SCALE_MAX_RESIST, startScale, endScale);
scaleInterpolator = t -> {
if (t < startResist) {
return t;
}
float resistProgress = Utilities.getProgress(t, startResist, 1);
resistProgress = RECENTS_SCALE_RESIST_INTERPOLATOR.getInterpolation(resistProgress);
return startResist + resistProgress * (maxResist - startResist);
};
}
resistAnim.addFloat(scaleTarget, scaleProperty, startScale, endScale,
scaleInterpolator);
AnimatorPlaybackController resistanceController = resistAnim.createPlaybackController();
return new AnimatorControllerWithResistance(normalController, resistanceController);
}
}
@@ -198,6 +198,7 @@ public class Interpolators {
public OvershootParams(float startProgress, float overshootPastProgress,
float endProgress, float velocityPxPerMs, int totalDistancePx, Context context) {
velocityPxPerMs = Math.abs(velocityPxPerMs);
overshootPastProgress = Math.max(overshootPastProgress, startProgress);
start = startProgress;
int startPx = (int) (start * totalDistancePx);
// Overshoot by about half a frame.