AlwaysCompletePerformance, ReversePerformance

These new PerformanceView classes are transforms over PerformanceViews.
The first is a cheap way to tell code that expects a performance to not
animate after all, and the other is a way to replace a view of a
performance going in one direction with a view of a performance going in
the other direction.

See also https://github.com/flutter/engine/issues/1708
This commit is contained in:
Hixie 2015-10-21 09:51:34 -07:00
parent 86087cbb08
commit 545db87ace

View file

@ -44,9 +44,19 @@ abstract class PerformanceView {
/// Stops calling the listener every time the status of the performance changes
void removeStatusListener(PerformanceStatusListener listener);
/// The current status of this animation
/// The current status of this animation.
PerformanceStatus get status;
/// The current direction of the animation.
AnimationDirection get direction;
/// The direction used to select the current curve.
///
/// The curve direction is only reset when we hit the beginning or the end of
/// the timeline to avoid discontinuities in the value of any variables this
/// performance is used to animate.
AnimationDirection get curveDirection;
/// The current progress of this animation (a value from 0.0 to 1.0).
/// This is the value that is used to update any variables when using updateVariable().
double get progress;
@ -58,6 +68,85 @@ abstract class PerformanceView {
bool get isCompleted => status == PerformanceStatus.completed;
}
class AlwaysCompletePerformance extends PerformanceView {
const AlwaysCompletePerformance();
void updateVariable(Animatable variable) {
variable.setProgress(1.0, AnimationDirection.forward);
}
// this performance never changes state
void addListener(PerformanceListener listener) { }
void removeListener(PerformanceListener listener) { }
void addStatusListener(PerformanceStatusListener listener) { }
void removeStatusListener(PerformanceStatusListener listener) { }
PerformanceStatus get status => PerformanceStatus.completed;
AnimationDirection get direction => AnimationDirection.forward;
AnimationDirection get curveDirection => AnimationDirection.forward;
double get progress => 1.0;
}
const AlwaysCompletePerformance alwaysCompletePerformance = const AlwaysCompletePerformance();
class ReversePerformance extends PerformanceView {
ReversePerformance(this.masterPerformance) {
masterPerformance.addStatusListener(_statusChangeHandler);
}
final PerformanceView masterPerformance;
void updateVariable(Animatable variable) {
variable.setProgress(progress, curveDirection);
}
void addListener(PerformanceListener listener) {
masterPerformance.addListener(listener);
}
void removeListener(PerformanceListener listener) {
masterPerformance.removeListener(listener);
}
final List<PerformanceStatusListener> _statusListeners = new List<PerformanceStatusListener>();
/// Calls listener every time the status of this performance changes
void addStatusListener(PerformanceStatusListener listener) {
_statusListeners.add(listener);
}
/// Stops calling the listener every time the status of this performance changes
void removeStatusListener(PerformanceStatusListener listener) {
_statusListeners.remove(listener);
}
void _statusChangeHandler(PerformanceStatus status) {
status = _reverseStatus(status);
List<PerformanceStatusListener> localListeners = new List<PerformanceStatusListener>.from(_statusListeners);
for (PerformanceStatusListener listener in localListeners)
listener(status);
}
PerformanceStatus get status => _reverseStatus(masterPerformance.status);
AnimationDirection get direction => _reverseDirection(masterPerformance.direction);
AnimationDirection get curveDirection => _reverseDirection(masterPerformance.curveDirection);
double get progress => 1.0 - masterPerformance.progress;
PerformanceStatus _reverseStatus(PerformanceStatus status) {
switch (status) {
case PerformanceStatus.forward: return PerformanceStatus.reverse;
case PerformanceStatus.reverse: return PerformanceStatus.forward;
case PerformanceStatus.completed: return PerformanceStatus.dismissed;
case PerformanceStatus.dismissed: return PerformanceStatus.completed;
}
}
AnimationDirection _reverseDirection(AnimationDirection direction) {
switch (direction) {
case AnimationDirection.forward: return AnimationDirection.reverse;
case AnimationDirection.reverse: return AnimationDirection.forward;
}
}
}
/// A timeline that can be reversed and used to update [Animatable]s.
///
/// For example, a performance may handle an animation of a menu opening by
@ -86,13 +175,9 @@ class Performance extends PerformanceView {
Duration duration;
SimulationStepper _timeline;
AnimationDirection get direction => _direction;
AnimationDirection _direction;
/// The direction used to select the current curve
///
/// Curve direction is only reset when we hit the beginning or the end of the
/// timeline to avoid discontinuities in the value of any variables this
/// performance is used to animate.
AnimationDirection get curveDirection => _curveDirection;
AnimationDirection _curveDirection;
/// If non-null, animate with this timing instead of a linear timing
@ -103,7 +188,6 @@ class Performance extends PerformanceView {
/// Note: Setting this value stops the current animation.
double get progress => _timeline.value.clamp(0.0, 1.0);
void set progress(double t) {
// TODO(mpcomplete): should this affect |direction|?
stop();
_timeline.value = t.clamp(0.0, 1.0);
_checkStatusChanged();