mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-04 01:46:49 +00:00
Improve animation when swiping down on task
- Scale icon down/up atomically at a threshold - Fix scale of tasks to properly take curve/zoom scale into account Bug: 78779525 Change-Id: I5909c63b18a993433de7a38b9641f4f38a219807
This commit is contained in:
@@ -15,7 +15,9 @@
|
||||
*/
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.PixelFormat;
|
||||
@@ -30,7 +32,7 @@ import com.android.quickstep.views.TaskView;
|
||||
|
||||
public class TaskViewDrawable extends Drawable {
|
||||
|
||||
public static FloatProperty<TaskViewDrawable> PROGRESS =
|
||||
public static final FloatProperty<TaskViewDrawable> PROGRESS =
|
||||
new FloatProperty<TaskViewDrawable>("progress") {
|
||||
@Override
|
||||
public void setValue(TaskViewDrawable taskViewDrawable, float v) {
|
||||
@@ -43,8 +45,10 @@ public class TaskViewDrawable extends Drawable {
|
||||
}
|
||||
};
|
||||
|
||||
private static final TimeInterpolator ICON_SIZE_INTERPOLATOR =
|
||||
(t) -> (Math.max(t, 0.3f) - 0.3f) / 0.7f;
|
||||
/**
|
||||
* The progress at which we play the atomic icon scale animation.
|
||||
*/
|
||||
private static final float ICON_SCALE_THRESHOLD = 0.95f;
|
||||
|
||||
private final RecentsView mParent;
|
||||
private final View mIconView;
|
||||
@@ -55,11 +59,15 @@ public class TaskViewDrawable extends Drawable {
|
||||
private final ClipAnimationHelper mClipAnimationHelper;
|
||||
|
||||
private float mProgress = 1;
|
||||
private boolean mPassedIconScaleThreshold;
|
||||
private ValueAnimator mIconScaleAnimator;
|
||||
private float mIconScale;
|
||||
|
||||
public TaskViewDrawable(TaskView tv, RecentsView parent) {
|
||||
mParent = parent;
|
||||
mIconView = tv.getIconView();
|
||||
mIconPos = new int[2];
|
||||
mIconScale = mIconView.getScaleX();
|
||||
Utilities.getDescendantCoordRelativeToAncestor(mIconView, parent, mIconPos, true);
|
||||
|
||||
mThumbnailView = tv.getThumbnail();
|
||||
@@ -70,6 +78,37 @@ public class TaskViewDrawable extends Drawable {
|
||||
public void setProgress(float progress) {
|
||||
mProgress = progress;
|
||||
mParent.invalidate();
|
||||
boolean passedIconScaleThreshold = progress <= ICON_SCALE_THRESHOLD;
|
||||
if (mPassedIconScaleThreshold != passedIconScaleThreshold) {
|
||||
mPassedIconScaleThreshold = passedIconScaleThreshold;
|
||||
animateIconScale(mPassedIconScaleThreshold ? 0 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void animateIconScale(float toScale) {
|
||||
if (mIconScaleAnimator != null) {
|
||||
mIconScaleAnimator.cancel();
|
||||
}
|
||||
mIconScaleAnimator = ValueAnimator.ofFloat(mIconScale, toScale);
|
||||
mIconScaleAnimator.addUpdateListener(valueAnimator -> {
|
||||
mIconScale = (float) valueAnimator.getAnimatedValue();
|
||||
if (mProgress > ICON_SCALE_THRESHOLD) {
|
||||
// Speed up the icon scale to ensure it is 1 when progress is 1.
|
||||
float iconProgress = (mProgress - ICON_SCALE_THRESHOLD) / (1 - ICON_SCALE_THRESHOLD);
|
||||
if (iconProgress > mIconScale) {
|
||||
mIconScale = iconProgress;
|
||||
}
|
||||
}
|
||||
invalidateSelf();
|
||||
});
|
||||
mIconScaleAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mIconScaleAnimator = null;
|
||||
}
|
||||
});
|
||||
mIconScaleAnimator.setDuration(TaskView.SCALE_ICON_DURATION);
|
||||
mIconScaleAnimator.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,8 +120,7 @@ public class TaskViewDrawable extends Drawable {
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(mIconPos[0], mIconPos[1]);
|
||||
float scale = ICON_SIZE_INTERPOLATOR.getInterpolation(mProgress);
|
||||
canvas.scale(scale, scale, mIconView.getWidth() / 2, mIconView.getHeight() / 2);
|
||||
canvas.scale(mIconScale, mIconScale, mIconView.getWidth() / 2, mIconView.getHeight() / 2);
|
||||
mIconView.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.TimeInterpolator;
|
||||
@@ -960,15 +961,13 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
if (currTask == null) {
|
||||
return;
|
||||
}
|
||||
currTask.setScaleX(mAdjacentScale);
|
||||
currTask.setScaleY(mAdjacentScale);
|
||||
currTask.setZoomScale(mAdjacentScale);
|
||||
|
||||
if (mCurrentPage - 1 >= 0) {
|
||||
TaskView adjacentTask = getPageAt(mCurrentPage - 1);
|
||||
float[] scaleAndTranslation = getAdjacentScaleAndTranslation(currTask, adjacentTask,
|
||||
mAdjacentScale, 0);
|
||||
adjacentTask.setScaleX(scaleAndTranslation[0]);
|
||||
adjacentTask.setScaleY(scaleAndTranslation[0]);
|
||||
adjacentTask.setZoomScale(scaleAndTranslation[0]);
|
||||
adjacentTask.setTranslationX(-scaleAndTranslation[1]);
|
||||
adjacentTask.setTranslationY(scaleAndTranslation[2]);
|
||||
}
|
||||
@@ -976,8 +975,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
TaskView adjacentTask = getPageAt(mCurrentPage + 1);
|
||||
float[] scaleAndTranslation = getAdjacentScaleAndTranslation(currTask, adjacentTask,
|
||||
mAdjacentScale, 0);
|
||||
adjacentTask.setScaleX(scaleAndTranslation[0]);
|
||||
adjacentTask.setScaleY(scaleAndTranslation[0]);
|
||||
adjacentTask.setZoomScale(scaleAndTranslation[0]);
|
||||
adjacentTask.setTranslationX(scaleAndTranslation[1]);
|
||||
adjacentTask.setTranslationY(scaleAndTranslation[2]);
|
||||
}
|
||||
@@ -986,7 +984,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
private float[] getAdjacentScaleAndTranslation(TaskView currTask, TaskView adjacentTask,
|
||||
float currTaskToScale, float currTaskToTranslationY) {
|
||||
float displacement = currTask.getWidth() * (currTaskToScale - currTask.getCurveScale());
|
||||
sTempFloatArray[0] = currTaskToScale * adjacentTask.getCurveScale();
|
||||
sTempFloatArray[0] = currTaskToScale;
|
||||
sTempFloatArray[1] = mIsRtl ? -displacement : displacement;
|
||||
sTempFloatArray[2] = currTaskToTranslationY;
|
||||
return sTempFloatArray;
|
||||
@@ -1127,13 +1125,15 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
return anim;
|
||||
}
|
||||
|
||||
private ObjectAnimator createAnimForChild(View child, float[] toScaleAndTranslation) {
|
||||
return ObjectAnimator.ofPropertyValuesHolder(child,
|
||||
private Animator createAnimForChild(TaskView child, float[] toScaleAndTranslation) {
|
||||
AnimatorSet anim = new AnimatorSet();
|
||||
anim.play(ObjectAnimator.ofFloat(child, TaskView.ZOOM_SCALE, toScaleAndTranslation[0]));
|
||||
anim.play(ObjectAnimator.ofPropertyValuesHolder(child,
|
||||
new PropertyListBuilder()
|
||||
.scale(child.getScaleX() * toScaleAndTranslation[0])
|
||||
.translationX(toScaleAndTranslation[1])
|
||||
.translationY(toScaleAndTranslation[2])
|
||||
.build());
|
||||
.build()));
|
||||
return anim;
|
||||
}
|
||||
|
||||
public PendingAnimation createTaskLauncherAnimation(TaskView tv, long duration) {
|
||||
|
||||
@@ -30,14 +30,15 @@ import android.graphics.Outline;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.util.Log;
|
||||
import android.util.Property;
|
||||
import android.view.View;
|
||||
import android.view.ViewOutlineProvider;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.R;
|
||||
@@ -76,12 +77,26 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
|
||||
*/
|
||||
private static final float EDGE_SCALE_DOWN_FACTOR = 0.03f;
|
||||
|
||||
private static final long SCALE_ICON_DURATION = 120;
|
||||
public static final long SCALE_ICON_DURATION = 120;
|
||||
|
||||
public static final Property<TaskView, Float> ZOOM_SCALE =
|
||||
new FloatProperty<TaskView>("zoomScale") {
|
||||
@Override
|
||||
public void setValue(TaskView taskView, float v) {
|
||||
taskView.setZoomScale(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(TaskView taskView) {
|
||||
return taskView.mZoomScale;
|
||||
}
|
||||
};
|
||||
|
||||
private Task mTask;
|
||||
private TaskThumbnailView mSnapshotView;
|
||||
private IconView mIconView;
|
||||
private float mCurveScale;
|
||||
private float mZoomScale;
|
||||
private float mCurveDimAlpha;
|
||||
private Animator mDimAlphaAnim;
|
||||
|
||||
@@ -207,8 +222,7 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
|
||||
}
|
||||
|
||||
public void resetVisualProperties() {
|
||||
setScaleX(1f);
|
||||
setScaleY(1f);
|
||||
setZoomScale(1);
|
||||
setTranslationX(0f);
|
||||
setTranslationY(0f);
|
||||
setTranslationZ(0);
|
||||
@@ -226,9 +240,7 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
|
||||
mSnapshotView.setDimAlpha(mCurveDimAlpha);
|
||||
}
|
||||
|
||||
mCurveScale = getCurveScaleForCurveInterpolation(curveInterpolation);
|
||||
setScaleX(mCurveScale);
|
||||
setScaleY(mCurveScale);
|
||||
setCurveScale(getCurveScaleForCurveInterpolation(curveInterpolation));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -247,10 +259,26 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
|
||||
return 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR;
|
||||
}
|
||||
|
||||
private void setCurveScale(float curveScale) {
|
||||
mCurveScale = curveScale;
|
||||
onScaleChanged();
|
||||
}
|
||||
|
||||
public float getCurveScale() {
|
||||
return mCurveScale;
|
||||
}
|
||||
|
||||
public void setZoomScale(float adjacentScale) {
|
||||
mZoomScale = adjacentScale;
|
||||
onScaleChanged();
|
||||
}
|
||||
|
||||
private void onScaleChanged() {
|
||||
float scale = mCurveScale * mZoomScale;
|
||||
setScaleX(scale);
|
||||
setScaleY(scale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOverlappingRendering() {
|
||||
// TODO: Clip-out the icon region from the thumbnail, since they are overlapping.
|
||||
|
||||
Reference in New Issue
Block a user