LockPatternView: Combine all cell activation animations.
Combine dot radius, dot color, line disappearing, line end animations together. It helps to reduce inconsistent states when one animation is cancelled and another is still running. Bug: 196067470 Change-Id: Ieac0bb3f329ac94924e3c5dd5a4a4e119404a56c (cherry picked from commit f5436912207f512493270ee5a1824b89f792aea4)
This commit is contained in:
@@ -80,6 +80,8 @@ public class LockPatternView extends View {
|
||||
private static final int LINE_FADE_OUT_DURATION_MILLIS = 500;
|
||||
private static final int LINE_FADE_OUT_DELAY_MILLIS = 150;
|
||||
private static final int DOT_ACTIVATION_DURATION_MILLIS = 50;
|
||||
private static final int DOT_RADIUS_INCREASE_DURATION_MILLIS = 96;
|
||||
private static final int DOT_RADIUS_DECREASE_DURATION_MILLIS = 192;
|
||||
private final CellState[][] mCellStates;
|
||||
|
||||
private final int mDotSize;
|
||||
@@ -245,9 +247,7 @@ public class LockPatternView extends View {
|
||||
public float lineEndX = Float.MIN_VALUE;
|
||||
public float lineEndY = Float.MIN_VALUE;
|
||||
@Nullable
|
||||
ValueAnimator lineEndAnimator;
|
||||
@Nullable
|
||||
ValueAnimator lineDisappearingAnimator;
|
||||
Animator activationAnimator;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -804,33 +804,39 @@ public class LockPatternView extends View {
|
||||
|
||||
private void startCellActivatedAnimation(Cell cell) {
|
||||
final CellState cellState = mCellStates[cell.row][cell.column];
|
||||
if (mDotSize != mDotSizeActivated) {
|
||||
startRadiusAnimation(mDotSize / 2, mDotSizeActivated / 2, 96,
|
||||
mLinearOutSlowInInterpolator,
|
||||
cellState, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
startRadiusAnimation(mDotSizeActivated / 2, mDotSize / 2, 192,
|
||||
mFastOutSlowInInterpolator,
|
||||
cellState, null);
|
||||
}
|
||||
});
|
||||
|
||||
if (cellState.activationAnimator != null) {
|
||||
cellState.activationAnimator.cancel();
|
||||
}
|
||||
startDotActivationColorAnimation(cellState);
|
||||
startLineEndAnimation(cellState, mInProgressX, mInProgressY,
|
||||
getCenterXForColumn(cell.column), getCenterYForRow(cell.row));
|
||||
startLineDisappearingAnimation(cellState);
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
AnimatorSet.Builder animatorSetBuilder = animatorSet
|
||||
.play(createLineDisappearingAnimation())
|
||||
.with(createLineEndAnimation(cellState, mInProgressX, mInProgressY,
|
||||
getCenterXForColumn(cell.column), getCenterYForRow(cell.row)));
|
||||
if (mDotSize != mDotSizeActivated) {
|
||||
animatorSetBuilder.with(createDotRadiusAnimation(cellState));
|
||||
}
|
||||
if (mDotColor != mDotActivatedColor) {
|
||||
animatorSetBuilder.with(createDotActivationColorAnimation(cellState));
|
||||
}
|
||||
|
||||
animatorSet.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
cellState.activationAnimator = null;
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
cellState.activationAnimator = animatorSet;
|
||||
animatorSet.start();
|
||||
}
|
||||
|
||||
private void startDotActivationColorAnimation(CellState cellState) {
|
||||
private Animator createDotActivationColorAnimation(CellState cellState) {
|
||||
ValueAnimator.AnimatorUpdateListener updateListener =
|
||||
new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator valueAnimator) {
|
||||
cellState.activationAnimationProgress =
|
||||
(float) valueAnimator.getAnimatedValue();
|
||||
invalidate();
|
||||
}
|
||||
valueAnimator -> {
|
||||
cellState.activationAnimationProgress =
|
||||
(float) valueAnimator.getAnimatedValue();
|
||||
invalidate();
|
||||
};
|
||||
ValueAnimator activateAnimator = ValueAnimator.ofFloat(0f, 1f);
|
||||
ValueAnimator deactivateAnimator = ValueAnimator.ofFloat(1f, 0f);
|
||||
@@ -847,82 +853,62 @@ public class LockPatternView extends View {
|
||||
.after(LINE_FADE_OUT_DELAY_MILLIS + LINE_FADE_OUT_DURATION_MILLIS
|
||||
- DOT_ACTIVATION_DURATION_MILLIS * 2)
|
||||
.after(activateAnimator);
|
||||
set.start();
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* On the last frame before cell activates the end point of in progress line is not aligned
|
||||
* with dot center so we execute a short animation moving the end point to exact dot center.
|
||||
*/
|
||||
private void startLineEndAnimation(final CellState state,
|
||||
private Animator createLineEndAnimation(final CellState state,
|
||||
final float startX, final float startY, final float targetX, final float targetY) {
|
||||
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
|
||||
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
float t = (float) animation.getAnimatedValue();
|
||||
state.lineEndX = (1 - t) * startX + t * targetX;
|
||||
state.lineEndY = (1 - t) * startY + t * targetY;
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
valueAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
state.lineEndAnimator = null;
|
||||
}
|
||||
valueAnimator.addUpdateListener(animation -> {
|
||||
float t = (float) animation.getAnimatedValue();
|
||||
state.lineEndX = (1 - t) * startX + t * targetX;
|
||||
state.lineEndY = (1 - t) * startY + t * targetY;
|
||||
invalidate();
|
||||
});
|
||||
valueAnimator.setInterpolator(mFastOutSlowInInterpolator);
|
||||
valueAnimator.setDuration(LINE_END_ANIMATION_DURATION_MILLIS);
|
||||
valueAnimator.start();
|
||||
state.lineEndAnimator = valueAnimator;
|
||||
return valueAnimator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts animator to fade out a line segment. It does only invalidate because all the
|
||||
* transitions are applied in {@code onDraw} method.
|
||||
*/
|
||||
private void startLineDisappearingAnimation(final CellState state) {
|
||||
private Animator createLineDisappearingAnimation() {
|
||||
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
|
||||
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
valueAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
state.lineDisappearingAnimator = null;
|
||||
}
|
||||
});
|
||||
valueAnimator.addUpdateListener(animation -> invalidate());
|
||||
valueAnimator.setStartDelay(LINE_FADE_OUT_DELAY_MILLIS);
|
||||
valueAnimator.setDuration(LINE_FADE_OUT_DURATION_MILLIS);
|
||||
valueAnimator.start();
|
||||
state.lineDisappearingAnimator = valueAnimator;
|
||||
return valueAnimator;
|
||||
}
|
||||
|
||||
private void startRadiusAnimation(float start, float end, long duration,
|
||||
Interpolator interpolator, final CellState state, final Runnable endRunnable) {
|
||||
ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end);
|
||||
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
state.radius = (float) animation.getAnimatedValue();
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
if (endRunnable != null) {
|
||||
valueAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
endRunnable.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
valueAnimator.setInterpolator(interpolator);
|
||||
valueAnimator.setDuration(duration);
|
||||
valueAnimator.start();
|
||||
private Animator createDotRadiusAnimation(CellState state) {
|
||||
float defaultRadius = mDotSize / 2f;
|
||||
float activatedRadius = mDotSizeActivated / 2f;
|
||||
|
||||
ValueAnimator.AnimatorUpdateListener animatorUpdateListener =
|
||||
animation -> {
|
||||
state.radius = (float) animation.getAnimatedValue();
|
||||
invalidate();
|
||||
};
|
||||
|
||||
ValueAnimator activationAnimator = ValueAnimator.ofFloat(defaultRadius, activatedRadius);
|
||||
activationAnimator.addUpdateListener(animatorUpdateListener);
|
||||
activationAnimator.setInterpolator(mLinearOutSlowInInterpolator);
|
||||
activationAnimator.setDuration(DOT_RADIUS_INCREASE_DURATION_MILLIS);
|
||||
|
||||
ValueAnimator deactivationAnimator = ValueAnimator.ofFloat(activatedRadius, defaultRadius);
|
||||
deactivationAnimator.addUpdateListener(animatorUpdateListener);
|
||||
deactivationAnimator.setInterpolator(mFastOutSlowInInterpolator);
|
||||
deactivationAnimator.setDuration(DOT_RADIUS_DECREASE_DURATION_MILLIS);
|
||||
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
set.playSequentially(activationAnimator, deactivationAnimator);
|
||||
return set;
|
||||
}
|
||||
|
||||
// helper method to find which cell a point maps to
|
||||
@@ -1136,16 +1122,14 @@ public class LockPatternView extends View {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
CellState state = mCellStates[i][j];
|
||||
if (state.lineEndAnimator != null) {
|
||||
state.lineEndAnimator.cancel();
|
||||
state.lineEndAnimator = null;
|
||||
if (state.activationAnimator != null) {
|
||||
state.activationAnimator.cancel();
|
||||
state.activationAnimator = null;
|
||||
state.radius = mDotSize / 2f;
|
||||
state.activationAnimationProgress = 0f;
|
||||
state.lineEndX = Float.MIN_VALUE;
|
||||
state.lineEndY = Float.MIN_VALUE;
|
||||
}
|
||||
if (state.lineDisappearingAnimator != null) {
|
||||
state.lineDisappearingAnimator.cancel();
|
||||
state.lineDisappearingAnimator = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user