Revert^2 "Improve AnimatorSet seekability."
2b73fe1025
Change-Id: Ic91371de1148cfb30c416e9091d529fc70a65e89
This commit is contained in:
committed by
Android (Google) Code Review
parent
2b73fe1025
commit
c2c30f7073
@@ -23,6 +23,7 @@ import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.pm.ActivityInfo.Config;
|
||||
import android.content.res.ConstantState;
|
||||
import android.os.Build;
|
||||
import android.util.LongArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -559,9 +560,36 @@ public abstract class Animator implements Cloneable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal use only.
|
||||
* Internal use only. Changes the value of the animator as if currentPlayTime has passed since
|
||||
* the start of the animation. Therefore, currentPlayTime includes the start delay, and any
|
||||
* repetition. lastPlayTime is similar and is used to calculate how many repeats have been
|
||||
* done between the two times.
|
||||
*/
|
||||
void animateBasedOnPlayTime(long currentPlayTime, long lastPlayTime, boolean inReverse) {}
|
||||
void animateValuesInRange(long currentPlayTime, long lastPlayTime) {}
|
||||
|
||||
/**
|
||||
* Internal use only. This animates any animation that has ended since lastPlayTime.
|
||||
* If an animation hasn't been finished, no change will be made.
|
||||
*/
|
||||
void animateSkipToEnds(long currentPlayTime, long lastPlayTime) {}
|
||||
|
||||
/**
|
||||
* Internal use only. Adds all start times (after delay) to and end times to times.
|
||||
* The value must include offset.
|
||||
*/
|
||||
void getStartAndEndTimes(LongArray times, long offset) {
|
||||
long startTime = offset + getStartDelay();
|
||||
if (times.indexOf(startTime) < 0) {
|
||||
times.add(startTime);
|
||||
}
|
||||
long duration = getTotalDuration();
|
||||
if (duration != DURATION_INFINITE) {
|
||||
long endTime = duration + offset;
|
||||
if (times.indexOf(endTime) < 0) {
|
||||
times.add(endTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>An animation listener receives notifications from an animation.
|
||||
|
||||
@@ -23,9 +23,11 @@ import android.os.Looper;
|
||||
import android.util.AndroidRuntimeException;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.LongArray;
|
||||
import android.view.animation.Animation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
@@ -181,6 +183,11 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
|
||||
*/
|
||||
private long mPauseTime = -1;
|
||||
|
||||
/**
|
||||
* The start and stop times of all descendant animators.
|
||||
*/
|
||||
private long[] mChildStartAndStopTimes;
|
||||
|
||||
// This is to work around a bug in b/34736819. This needs to be removed once app team
|
||||
// fixes their side.
|
||||
private AnimatorListenerAdapter mAnimationEndListener = new AnimatorListenerAdapter() {
|
||||
@@ -779,26 +786,25 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
|
||||
|
||||
@Override
|
||||
void skipToEndValue(boolean inReverse) {
|
||||
if (!isInitialized()) {
|
||||
throw new UnsupportedOperationException("Children must be initialized.");
|
||||
}
|
||||
|
||||
// This makes sure the animation events are sorted an up to date.
|
||||
initAnimation();
|
||||
initChildren();
|
||||
|
||||
// Calling skip to the end in the sequence that they would be called in a forward/reverse
|
||||
// run, such that the sequential animations modifying the same property would have
|
||||
// the right value in the end.
|
||||
if (inReverse) {
|
||||
for (int i = mEvents.size() - 1; i >= 0; i--) {
|
||||
if (mEvents.get(i).mEvent == AnimationEvent.ANIMATION_DELAY_ENDED) {
|
||||
mEvents.get(i).mNode.mAnimation.skipToEndValue(true);
|
||||
AnimationEvent event = mEvents.get(i);
|
||||
if (event.mEvent == AnimationEvent.ANIMATION_DELAY_ENDED) {
|
||||
event.mNode.mAnimation.skipToEndValue(true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < mEvents.size(); i++) {
|
||||
if (mEvents.get(i).mEvent == AnimationEvent.ANIMATION_END) {
|
||||
mEvents.get(i).mNode.mAnimation.skipToEndValue(false);
|
||||
AnimationEvent event = mEvents.get(i);
|
||||
if (event.mEvent == AnimationEvent.ANIMATION_END) {
|
||||
event.mNode.mAnimation.skipToEndValue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -814,72 +820,181 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
|
||||
* {@link android.view.animation.Animation.AnimationListener#onAnimationRepeat(Animation)},
|
||||
* as needed, based on the last play time and current play time.
|
||||
*/
|
||||
@Override
|
||||
void animateBasedOnPlayTime(long currentPlayTime, long lastPlayTime, boolean inReverse) {
|
||||
if (currentPlayTime < 0 || lastPlayTime < 0) {
|
||||
private void animateBasedOnPlayTime(
|
||||
long currentPlayTime,
|
||||
long lastPlayTime,
|
||||
boolean inReverse
|
||||
) {
|
||||
if (currentPlayTime < 0 || lastPlayTime < -1) {
|
||||
throw new UnsupportedOperationException("Error: Play time should never be negative.");
|
||||
}
|
||||
// TODO: take into account repeat counts and repeat callback when repeat is implemented.
|
||||
// Clamp currentPlayTime and lastPlayTime
|
||||
|
||||
// TODO: Make this more efficient
|
||||
|
||||
// Convert the play times to the forward direction.
|
||||
if (inReverse) {
|
||||
if (getTotalDuration() == DURATION_INFINITE) {
|
||||
throw new UnsupportedOperationException("Cannot reverse AnimatorSet with infinite"
|
||||
+ " duration");
|
||||
long duration = getTotalDuration();
|
||||
if (duration == DURATION_INFINITE) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot reverse AnimatorSet with infinite duration"
|
||||
);
|
||||
}
|
||||
long duration = getTotalDuration() - mStartDelay;
|
||||
// Convert the play times to the forward direction.
|
||||
currentPlayTime = Math.min(currentPlayTime, duration);
|
||||
currentPlayTime = duration - currentPlayTime;
|
||||
lastPlayTime = duration - lastPlayTime;
|
||||
inReverse = false;
|
||||
}
|
||||
|
||||
ArrayList<Node> unfinishedNodes = new ArrayList<>();
|
||||
// Assumes forward playing from here on.
|
||||
for (int i = 0; i < mEvents.size(); i++) {
|
||||
AnimationEvent event = mEvents.get(i);
|
||||
if (event.getTime() > currentPlayTime || event.getTime() == DURATION_INFINITE) {
|
||||
break;
|
||||
}
|
||||
long[] startEndTimes = ensureChildStartAndEndTimes();
|
||||
int index = findNextIndex(lastPlayTime, startEndTimes);
|
||||
int endIndex = findNextIndex(currentPlayTime, startEndTimes);
|
||||
|
||||
// This animation started prior to the current play time, and won't finish before the
|
||||
// play time, add to the unfinished list.
|
||||
if (event.mEvent == AnimationEvent.ANIMATION_DELAY_ENDED) {
|
||||
if (event.mNode.mEndTime == DURATION_INFINITE
|
||||
|| event.mNode.mEndTime > currentPlayTime) {
|
||||
unfinishedNodes.add(event.mNode);
|
||||
// Change values at the start/end times so that values are set in the right order.
|
||||
// We don't want an animator that would finish before another to override the value
|
||||
// set by another animator that finishes earlier.
|
||||
if (currentPlayTime >= lastPlayTime) {
|
||||
while (index < endIndex) {
|
||||
long playTime = startEndTimes[index];
|
||||
if (lastPlayTime != playTime) {
|
||||
animateSkipToEnds(playTime, lastPlayTime);
|
||||
animateValuesInRange(playTime, lastPlayTime);
|
||||
lastPlayTime = playTime;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
} else {
|
||||
while (index > endIndex) {
|
||||
index--;
|
||||
long playTime = startEndTimes[index];
|
||||
if (lastPlayTime != playTime) {
|
||||
animateSkipToEnds(playTime, lastPlayTime);
|
||||
animateValuesInRange(playTime, lastPlayTime);
|
||||
lastPlayTime = playTime;
|
||||
}
|
||||
}
|
||||
// For animations that do finish before the play time, end them in the sequence that
|
||||
// they would in a normal run.
|
||||
if (event.mEvent == AnimationEvent.ANIMATION_END) {
|
||||
// Skip to the end of the animation.
|
||||
event.mNode.mAnimation.skipToEndValue(false);
|
||||
}
|
||||
if (currentPlayTime != lastPlayTime) {
|
||||
animateSkipToEnds(currentPlayTime, lastPlayTime);
|
||||
animateValuesInRange(currentPlayTime, lastPlayTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks through startEndTimes for playTime. If it is in startEndTimes, the index after
|
||||
* is returned. Otherwise, it returns the index at which it would be placed if it were
|
||||
* to be inserted.
|
||||
*/
|
||||
private int findNextIndex(long playTime, long[] startEndTimes) {
|
||||
int index = Arrays.binarySearch(startEndTimes, playTime);
|
||||
if (index < 0) {
|
||||
index = -index - 1;
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
void animateSkipToEnds(long currentPlayTime, long lastPlayTime) {
|
||||
initAnimation();
|
||||
|
||||
if (lastPlayTime > currentPlayTime) {
|
||||
for (int i = mEvents.size() - 1; i >= 0; i--) {
|
||||
AnimationEvent event = mEvents.get(i);
|
||||
Node node = event.mNode;
|
||||
if (event.mEvent == AnimationEvent.ANIMATION_END
|
||||
&& node.mStartTime != DURATION_INFINITE
|
||||
) {
|
||||
Animator animator = node.mAnimation;
|
||||
long start = node.mStartTime + animator.getStartDelay();
|
||||
long end = node.mTotalDuration == DURATION_INFINITE
|
||||
? Long.MAX_VALUE : node.mEndTime;
|
||||
if (currentPlayTime <= start && start < lastPlayTime) {
|
||||
animator.animateSkipToEnds(
|
||||
start - node.mStartTime,
|
||||
lastPlayTime - node.mStartTime
|
||||
);
|
||||
} else if (start <= currentPlayTime && currentPlayTime <= end) {
|
||||
animator.animateSkipToEnds(
|
||||
currentPlayTime - node.mStartTime,
|
||||
lastPlayTime - node.mStartTime
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int eventsSize = mEvents.size();
|
||||
for (int i = 0; i < eventsSize; i++) {
|
||||
AnimationEvent event = mEvents.get(i);
|
||||
Node node = event.mNode;
|
||||
if (event.mEvent == AnimationEvent.ANIMATION_DELAY_ENDED
|
||||
&& node.mStartTime != DURATION_INFINITE
|
||||
) {
|
||||
Animator animator = node.mAnimation;
|
||||
long start = node.mStartTime + animator.getStartDelay();
|
||||
long end = node.mTotalDuration == DURATION_INFINITE
|
||||
? Long.MAX_VALUE : node.mEndTime;
|
||||
if (lastPlayTime < end && end <= currentPlayTime) {
|
||||
animator.animateSkipToEnds(
|
||||
end - node.mStartTime,
|
||||
lastPlayTime - node.mStartTime
|
||||
);
|
||||
} else if (start <= currentPlayTime && currentPlayTime <= end) {
|
||||
animator.animateSkipToEnds(
|
||||
currentPlayTime - node.mStartTime,
|
||||
lastPlayTime - node.mStartTime
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Seek unfinished animation to the right time.
|
||||
for (int i = 0; i < unfinishedNodes.size(); i++) {
|
||||
Node node = unfinishedNodes.get(i);
|
||||
long playTime = getPlayTimeForNode(currentPlayTime, node, inReverse);
|
||||
if (!inReverse) {
|
||||
playTime -= node.mAnimation.getStartDelay();
|
||||
}
|
||||
node.mAnimation.animateBasedOnPlayTime(playTime, lastPlayTime, inReverse);
|
||||
}
|
||||
@Override
|
||||
void animateValuesInRange(long currentPlayTime, long lastPlayTime) {
|
||||
initAnimation();
|
||||
|
||||
// Seek not yet started animations.
|
||||
for (int i = 0; i < mEvents.size(); i++) {
|
||||
int eventsSize = mEvents.size();
|
||||
for (int i = 0; i < eventsSize; i++) {
|
||||
AnimationEvent event = mEvents.get(i);
|
||||
if (event.getTime() > currentPlayTime
|
||||
&& event.mEvent == AnimationEvent.ANIMATION_DELAY_ENDED) {
|
||||
event.mNode.mAnimation.skipToEndValue(true);
|
||||
Node node = event.mNode;
|
||||
if (event.mEvent == AnimationEvent.ANIMATION_DELAY_ENDED
|
||||
&& node.mStartTime != DURATION_INFINITE
|
||||
) {
|
||||
Animator animator = node.mAnimation;
|
||||
long start = node.mStartTime + animator.getStartDelay();
|
||||
long end = node.mTotalDuration == DURATION_INFINITE
|
||||
? Long.MAX_VALUE : node.mEndTime;
|
||||
if (start < currentPlayTime && currentPlayTime < end) {
|
||||
animator.animateValuesInRange(
|
||||
currentPlayTime - node.mStartTime,
|
||||
Math.max(-1, lastPlayTime - node.mStartTime)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long[] ensureChildStartAndEndTimes() {
|
||||
if (mChildStartAndStopTimes == null) {
|
||||
LongArray startAndEndTimes = new LongArray();
|
||||
getStartAndEndTimes(startAndEndTimes, 0);
|
||||
long[] times = startAndEndTimes.toArray();
|
||||
Arrays.sort(times);
|
||||
mChildStartAndStopTimes = times;
|
||||
}
|
||||
return mChildStartAndStopTimes;
|
||||
}
|
||||
|
||||
@Override
|
||||
void getStartAndEndTimes(LongArray times, long offset) {
|
||||
int eventsSize = mEvents.size();
|
||||
for (int i = 0; i < eventsSize; i++) {
|
||||
AnimationEvent event = mEvents.get(i);
|
||||
if (event.mEvent == AnimationEvent.ANIMATION_DELAY_ENDED
|
||||
&& event.mNode.mStartTime != DURATION_INFINITE
|
||||
) {
|
||||
event.mNode.mAnimation.getStartAndEndTimes(times, offset + event.mNode.mStartTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -899,10 +1014,6 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
|
||||
return mChildrenInitialized;
|
||||
}
|
||||
|
||||
private void skipToStartValue(boolean inReverse) {
|
||||
skipToEndValue(!inReverse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position of the animation to the specified point in time. This time should
|
||||
* be between 0 and the total duration of the animation, including any repetition. If
|
||||
@@ -926,23 +1037,25 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
|
||||
if ((getTotalDuration() != DURATION_INFINITE && playTime > getTotalDuration() - mStartDelay)
|
||||
|| playTime < 0) {
|
||||
throw new UnsupportedOperationException("Error: Play time should always be in between"
|
||||
+ "0 and duration.");
|
||||
+ " 0 and duration.");
|
||||
}
|
||||
|
||||
initAnimation();
|
||||
|
||||
if (!isStarted() || isPaused()) {
|
||||
if (mReversing) {
|
||||
if (mReversing && !isStarted()) {
|
||||
throw new UnsupportedOperationException("Error: Something went wrong. mReversing"
|
||||
+ " should not be set when AnimatorSet is not started.");
|
||||
}
|
||||
long lastPlayTime = mSeekState.getPlayTime();
|
||||
if (!mSeekState.isActive()) {
|
||||
findLatestEventIdForTime(0);
|
||||
// Set all the values to start values.
|
||||
initChildren();
|
||||
// Set all the values to start values.
|
||||
skipToEndValue(!mReversing);
|
||||
mSeekState.setPlayTime(0, mReversing);
|
||||
}
|
||||
animateBasedOnPlayTime(playTime, 0, mReversing);
|
||||
animateBasedOnPlayTime(playTime, lastPlayTime, mReversing);
|
||||
mSeekState.setPlayTime(playTime, mReversing);
|
||||
} else {
|
||||
// If the animation is running, just set the seek time and wait until the next frame
|
||||
@@ -981,10 +1094,16 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
|
||||
private void initChildren() {
|
||||
if (!isInitialized()) {
|
||||
mChildrenInitialized = true;
|
||||
// Forcefully initialize all children based on their end time, so that if the start
|
||||
// value of a child is dependent on a previous animation, the animation will be
|
||||
// initialized after the the previous animations have been advanced to the end.
|
||||
skipToEndValue(false);
|
||||
|
||||
// We have to initialize all the start values so that they are based on the previous
|
||||
// values.
|
||||
long[] times = ensureChildStartAndEndTimes();
|
||||
|
||||
long previousTime = -1;
|
||||
for (long time : times) {
|
||||
animateBasedOnPlayTime(time, previousTime, false);
|
||||
previousTime = time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1058,7 +1177,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
|
||||
for (int i = 0; i < mPlayingSet.size(); i++) {
|
||||
Node node = mPlayingSet.get(i);
|
||||
if (!node.mEnded) {
|
||||
pulseFrame(node, getPlayTimeForNode(unscaledPlayTime, node));
|
||||
pulseFrame(node, getPlayTimeForNodeIncludingDelay(unscaledPlayTime, node));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1129,7 +1248,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
|
||||
pulseFrame(node, 0);
|
||||
} else if (event.mEvent == AnimationEvent.ANIMATION_DELAY_ENDED && !node.mEnded) {
|
||||
// end event:
|
||||
pulseFrame(node, getPlayTimeForNode(playTime, node));
|
||||
pulseFrame(node, getPlayTimeForNodeIncludingDelay(playTime, node));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1150,7 +1269,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
|
||||
pulseFrame(node, 0);
|
||||
} else if (event.mEvent == AnimationEvent.ANIMATION_END && !node.mEnded) {
|
||||
// start event:
|
||||
pulseFrame(node, getPlayTimeForNode(playTime, node));
|
||||
pulseFrame(node, getPlayTimeForNodeIncludingDelay(playTime, node));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1172,11 +1291,15 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
|
||||
}
|
||||
}
|
||||
|
||||
private long getPlayTimeForNode(long overallPlayTime, Node node) {
|
||||
return getPlayTimeForNode(overallPlayTime, node, mReversing);
|
||||
private long getPlayTimeForNodeIncludingDelay(long overallPlayTime, Node node) {
|
||||
return getPlayTimeForNodeIncludingDelay(overallPlayTime, node, mReversing);
|
||||
}
|
||||
|
||||
private long getPlayTimeForNode(long overallPlayTime, Node node, boolean inReverse) {
|
||||
private long getPlayTimeForNodeIncludingDelay(
|
||||
long overallPlayTime,
|
||||
Node node,
|
||||
boolean inReverse
|
||||
) {
|
||||
if (inReverse) {
|
||||
overallPlayTime = getTotalDuration() - overallPlayTime;
|
||||
return node.mEndTime - overallPlayTime;
|
||||
@@ -1198,26 +1321,8 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
|
||||
}
|
||||
// Set the child animators to the right end:
|
||||
if (mShouldResetValuesAtStart) {
|
||||
if (isInitialized()) {
|
||||
skipToEndValue(!mReversing);
|
||||
} else if (mReversing) {
|
||||
// Reversing but haven't initialized all the children yet.
|
||||
initChildren();
|
||||
skipToEndValue(!mReversing);
|
||||
} else {
|
||||
// If not all children are initialized and play direction is forward
|
||||
for (int i = mEvents.size() - 1; i >= 0; i--) {
|
||||
if (mEvents.get(i).mEvent == AnimationEvent.ANIMATION_DELAY_ENDED) {
|
||||
Animator anim = mEvents.get(i).mNode.mAnimation;
|
||||
// Only reset the animations that have been initialized to start value,
|
||||
// so that if they are defined without a start value, they will get the
|
||||
// values set at the right time (i.e. the next animation run)
|
||||
if (anim.isInitialized()) {
|
||||
anim.skipToEndValue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
initChildren();
|
||||
skipToEndValue(!mReversing);
|
||||
}
|
||||
|
||||
if (mReversing || mStartDelay == 0 || mSeekState.isActive()) {
|
||||
@@ -1922,11 +2027,11 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
|
||||
}
|
||||
|
||||
void setPlayTime(long playTime, boolean inReverse) {
|
||||
// TODO: This can be simplified.
|
||||
|
||||
// Clamp the play time
|
||||
if (getTotalDuration() != DURATION_INFINITE) {
|
||||
mPlayTime = Math.min(playTime, getTotalDuration() - mStartDelay);
|
||||
} else {
|
||||
mPlayTime = playTime;
|
||||
}
|
||||
mPlayTime = Math.max(0, mPlayTime);
|
||||
mSeekingInReverse = inReverse;
|
||||
|
||||
@@ -324,8 +324,9 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
|
||||
listenerCopy = new ArrayList<>(sDurationScaleChangeListeners);
|
||||
}
|
||||
|
||||
for (WeakReference<DurationScaleChangeListener> listenerRef : listenerCopy) {
|
||||
final DurationScaleChangeListener listener = listenerRef.get();
|
||||
int listenersSize = listenerCopy.size();
|
||||
for (int i = 0; i < listenersSize; i++) {
|
||||
final DurationScaleChangeListener listener = listenerCopy.get(i).get();
|
||||
if (listener != null) {
|
||||
listener.onChanged(durationScale);
|
||||
}
|
||||
@@ -624,7 +625,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
|
||||
public void setValues(PropertyValuesHolder... values) {
|
||||
int numValues = values.length;
|
||||
mValues = values;
|
||||
mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
|
||||
mValuesMap = new HashMap<>(numValues);
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
PropertyValuesHolder valuesHolder = values[i];
|
||||
mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
|
||||
@@ -658,9 +659,11 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
|
||||
@CallSuper
|
||||
void initAnimation() {
|
||||
if (!mInitialized) {
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].init();
|
||||
if (mValues != null) {
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].init();
|
||||
}
|
||||
}
|
||||
mInitialized = true;
|
||||
}
|
||||
@@ -1209,10 +1212,14 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
|
||||
// If it's not yet running, then start listeners weren't called. Call them now.
|
||||
notifyStartListeners();
|
||||
}
|
||||
ArrayList<AnimatorListener> tmpListeners =
|
||||
(ArrayList<AnimatorListener>) mListeners.clone();
|
||||
for (AnimatorListener listener : tmpListeners) {
|
||||
listener.onAnimationCancel(this);
|
||||
int listenersSize = mListeners.size();
|
||||
if (listenersSize > 0) {
|
||||
ArrayList<AnimatorListener> tmpListeners =
|
||||
(ArrayList<AnimatorListener>) mListeners.clone();
|
||||
for (int i = 0; i < listenersSize; i++) {
|
||||
AnimatorListener listener = tmpListeners.get(i);
|
||||
listener.onAnimationCancel(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
endAnimation();
|
||||
@@ -1452,12 +1459,19 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
|
||||
* will be called.
|
||||
*/
|
||||
@Override
|
||||
void animateBasedOnPlayTime(long currentPlayTime, long lastPlayTime, boolean inReverse) {
|
||||
if (currentPlayTime < 0 || lastPlayTime < 0) {
|
||||
void animateValuesInRange(long currentPlayTime, long lastPlayTime) {
|
||||
if (currentPlayTime < mStartDelay || lastPlayTime < -1) {
|
||||
throw new UnsupportedOperationException("Error: Play time should never be negative.");
|
||||
}
|
||||
|
||||
initAnimation();
|
||||
long duration = getTotalDuration();
|
||||
if (duration >= 0) {
|
||||
lastPlayTime = Math.min(duration, lastPlayTime);
|
||||
}
|
||||
lastPlayTime -= mStartDelay;
|
||||
currentPlayTime -= mStartDelay;
|
||||
|
||||
// Check whether repeat callback is needed only when repeat count is non-zero
|
||||
if (mRepeatCount > 0) {
|
||||
int iteration = (int) (currentPlayTime / mDuration);
|
||||
@@ -1478,15 +1492,27 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
|
||||
}
|
||||
|
||||
if (mRepeatCount != INFINITE && currentPlayTime >= (mRepeatCount + 1) * mDuration) {
|
||||
skipToEndValue(inReverse);
|
||||
throw new IllegalStateException("Can't animate a value outside of the duration");
|
||||
} else {
|
||||
// Find the current fraction:
|
||||
float fraction = currentPlayTime / (float) mDuration;
|
||||
fraction = getCurrentIterationFraction(fraction, inReverse);
|
||||
fraction = getCurrentIterationFraction(fraction, false);
|
||||
animateValue(fraction);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void animateSkipToEnds(long currentPlayTime, long lastPlayTime) {
|
||||
if (currentPlayTime <= mStartDelay && lastPlayTime > mStartDelay) {
|
||||
skipToEndValue(true);
|
||||
} else {
|
||||
long duration = getTotalDuration();
|
||||
if (duration >= 0 && currentPlayTime >= duration && lastPlayTime < duration) {
|
||||
skipToEndValue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal use only.
|
||||
* Skips the animation value to end/start, depending on whether the play direction is forward
|
||||
@@ -1641,6 +1667,9 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
|
||||
Trace.traceCounter(Trace.TRACE_TAG_VIEW, getNameForTrace() + hashCode(),
|
||||
(int) (fraction * 1000));
|
||||
}
|
||||
if (mValues == null) {
|
||||
return;
|
||||
}
|
||||
fraction = mInterpolator.getInterpolation(fraction);
|
||||
mCurrentFraction = fraction;
|
||||
int numValues = mValues.length;
|
||||
|
||||
Reference in New Issue
Block a user