Commit 3b62185f authored by Hixie's avatar Hixie

Simplify AnimationPerformance

AnimationPerformance had some logic for supporting multiple variables
that was hardly ever used. ValueAnimation, a subclass, has logic for
handling a single variable. I've removed the logic for handling
variables from AnimationPerformance in favour of most call sites instead
using ValueAnimation.
parent 347bd25c
......@@ -43,7 +43,7 @@ abstract class WatchableAnimationPerformance {
void removeStatusListener(AnimationPerformanceStatusListener listener);
}
/// A collection of values that animated based on a timeline
/// A timeline that can be reversed and used to update [AnimatedVariable]s.
///
/// For example, a performance may handle an animation of a menu opening by
/// sliding and fading in (changing Y value and opacity) over .5 seconds. The
......@@ -52,9 +52,10 @@ abstract class WatchableAnimationPerformance {
/// [fling] the timeline causing a physics-based simulation to take over the
/// progression.
class AnimationPerformance implements WatchableAnimationPerformance {
AnimationPerformance({ AnimatedVariable variable, this.duration }) :
_variable = variable {
AnimationPerformance({ this.duration, double progress }) {
_timeline = new Timeline(_tick);
if (progress != null)
_timeline.value = progress.clamp(0.0, 1.0);
}
/// Returns a [WatchableAnimationPerformance] for this performance,
......@@ -65,18 +66,14 @@ class AnimationPerformance implements WatchableAnimationPerformance {
/// The length of time this performance should last
Duration duration;
/// The variable being updated by this performance
AnimatedVariable get variable => _variable;
void set variable(AnimatedVariable variable) { _variable = variable; }
AnimatedVariable _variable;
Timeline _timeline;
Direction _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 the variable.
/// timeline to avoid discontinuities in the value of any variables this
/// performance is used to animate.
Direction _curveDirection;
/// If non-null, animate with this timing instead of a linear timing
......@@ -85,21 +82,6 @@ class AnimationPerformance implements WatchableAnimationPerformance {
/// If non-null, animate with this force instead of a zero-to-one timeline.
Force attachedForce;
/// Add a variable to this animation
///
/// If there are no attached variables, this variable becomes the value of
/// [variable]. Otherwise, all the variables are stored in an [AnimatedList].
void addVariable(AnimatedVariable newVariable) {
if (variable == null) {
variable = newVariable;
} else if (variable is AnimatedList) {
final AnimatedList variable = this.variable; // TODO(ianh): Remove this line when the analyzer is cleverer
variable.variables.add(newVariable);
} else {
variable = new AnimatedList([variable, newVariable]);
}
}
/// The progress of this performance along the timeline
///
/// Note: Setting this value stops the current animation.
......@@ -238,8 +220,10 @@ class AnimationPerformance implements WatchableAnimationPerformance {
void _tick(double t) {
_updateCurveDirection();
if (variable != null)
variable.setProgress(_curvedProgress, _curveDirection);
didTick(t);
}
void didTick(double t) {
_notifyListeners();
_checkStatusChanged();
}
......@@ -247,11 +231,15 @@ class AnimationPerformance implements WatchableAnimationPerformance {
/// An animation performance with an animated variable with a concrete type
class ValueAnimation<T> extends AnimationPerformance {
ValueAnimation({ AnimatedValue<T> variable, Duration duration }) :
super(variable: variable, duration: duration);
AnimatedValue<T> get variable => _variable as AnimatedValue<T>;
void set variable(AnimatedValue<T> v) { _variable = v; }
ValueAnimation({ this.variable, Duration duration, double progress }) :
super(duration: duration, progress: progress);
AnimatedValue<T> variable;
T get value => variable.value;
void didTick(double t) {
if (variable != null)
variable.setProgress(_curvedProgress, _curveDirection);
super.didTick(t);
}
}
......@@ -131,7 +131,7 @@ class _RenderCheckbox extends RenderToggleable {
..color = uncheckedColor;
// The rrect contracts slightly during the animation
double inset = 2.0 - (position.value - _kMidpoint).abs() * 2.0;
double inset = 2.0 - (position - _kMidpoint).abs() * 2.0;
sky.Rect rect = new sky.Rect.fromLTWH(offset.dx + inset, offset.dy + inset,
_kEdgeSize - inset, _kEdgeSize - inset);
sky.RRect rrect = new sky.RRect()
......@@ -142,19 +142,19 @@ class _RenderCheckbox extends RenderToggleable {
canvas.drawRRect(rrect, paint);
// Radial gradient that changes size
if (position.value > 0) {
if (position > 0) {
paint.setStyle(sky.PaintingStyle.fill);
paint.setShader(new sky.Gradient.radial(
new Point(_kEdgeSize / 2.0, _kEdgeSize / 2.0),
_kEdgeSize * (_kMidpoint - position.value) * 8.0, [
_kEdgeSize * (_kMidpoint - position) * 8.0, [
const sky.Color(0x00000000),
uncheckedColor
]));
canvas.drawRRect(rrect, paint);
}
if (position.value > _kMidpoint) {
double t = (position.value - _kMidpoint) / (1.0 - _kMidpoint);
if (position > _kMidpoint) {
double t = (position - _kMidpoint) / (1.0 - _kMidpoint);
// Solid filled rrect
paint.setStyle(sky.PaintingStyle.strokeAndFill);
......
......@@ -30,11 +30,11 @@ class InkSplash {
_radius = new AnimatedValue<double>(
_kSplashInitialSize, end: _targetRadius, curve: easeOut);
_performance = new AnimationPerformance()
..variable = _radius
..duration = new Duration(milliseconds: (_targetRadius / _kSplashUnconfirmedVelocity).floor())
..addListener(_handleRadiusChange)
..play();
_performance = new ValueAnimation<double>(
variable: _radius,
duration: new Duration(milliseconds: (_targetRadius / _kSplashUnconfirmedVelocity).floor())
)..addListener(_handleRadiusChange)
..play();
}
final int pointer;
......
......@@ -35,11 +35,15 @@ abstract class ProgressIndicator extends StatefulComponent {
}
class ProgressIndicatorState extends State<ProgressIndicator> {
ValueAnimation<double> _performance;
void initState() {
super.initState();
_performance = new AnimationPerformance()
..duration = const Duration(milliseconds: 1500)
..variable = new AnimatedValue<double>(0.0, end: 1.0, curve: ease);
_performance = new ValueAnimation<double>(
variable: new AnimatedValue<double>(0.0, end: 1.0, curve: ease),
duration: const Duration(milliseconds: 1500)
);
_performance.addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed)
_restartAnimation();
......@@ -47,9 +51,6 @@ class ProgressIndicatorState extends State<ProgressIndicator> {
_performance.play();
}
AnimationPerformance _performance;
double get _performanceValue => (_performance.variable as AnimatedValue<double>).value;
void _restartAnimation() {
_performance.progress = 0.0;
_performance.play();
......@@ -57,13 +58,13 @@ class ProgressIndicatorState extends State<ProgressIndicator> {
Widget build(BuildContext context) {
if (config.value != null)
return config._buildIndicator(context, _performanceValue);
return config._buildIndicator(context, _performance.value);
return new BuilderTransition(
variables: [_performance.variable],
performance: _performance.view,
builder: (BuildContext context) {
return config._buildIndicator(context, _performanceValue);
return config._buildIndicator(context, _performance.value);
}
);
}
......
......@@ -97,9 +97,9 @@ class _RenderSwitch extends RenderToggleable {
_radialReaction = new RadialReaction(
center: new Point(_kSwitchSize.width / 2.0, _kSwitchSize.height / 2.0),
radius: _kReactionRadius,
startPosition: startLocation)
..addListener(markNeedsPaint)
..show();
startPosition: startLocation
)..addListener(markNeedsPaint)
..show();
}
Future _hideRadialReaction() async {
......@@ -140,10 +140,10 @@ class _RenderSwitch extends RenderToggleable {
paint.drawLooper = builder.build();
// The thumb contracts slightly during the animation
double inset = 2.0 - (position.value - 0.5).abs() * 2.0;
double inset = 2.0 - (position - 0.5).abs() * 2.0;
Point thumbPos = new Point(offset.dx +
_kTrackRadius +
position.value * (_kTrackWidth - _kTrackRadius * 2),
position * (_kTrackWidth - _kTrackRadius * 2),
offset.dy + _kSwitchHeight / 2.0);
canvas.drawCircle(thumbPos, _kThumbRadius - inset, paint);
}
......
......@@ -30,16 +30,16 @@ class RadialReaction {
_outerOpacity = new AnimatedValue<double>(0.0, end: _kMaxOpacity, curve: easeOut);
_innerCenter = new AnimatedValue<Point>(startPosition, end: center, curve: easeOut);
_innerRadius = new AnimatedValue<double>(0.0, end: radius, curve: easeOut);
_showPerformance = new AnimationPerformance()
..addVariable(_outerOpacity)
..addVariable(_innerCenter)
..addVariable(_innerRadius)
..duration = _kShowDuration;
_fade = new AnimatedValue(1.0, end: 0.0, curve: easeIn);
_hidePerformance = new AnimationPerformance()
..addVariable(_fade)
..duration =_kHideDuration;
_showPerformance = new AnimationPerformance(duration: _kShowDuration)
..addListener(() {
_showPerformance.updateVariable(_outerOpacity);
_showPerformance.updateVariable(_innerCenter);
_showPerformance.updateVariable(_innerRadius);
});
_fade = new ValueAnimation<double>(
variable: new AnimatedValue(1.0, end: 0.0, curve: easeIn),
duration: _kHideDuration
);
}
/// The center of the circle in which the reaction occurs
......@@ -55,8 +55,7 @@ class RadialReaction {
Future _showComplete;
AnimationPerformance _hidePerformance;
AnimatedValue<double> _fade;
ValueAnimation<double> _fade;
/// Show the reaction
///
......@@ -70,13 +69,13 @@ class RadialReaction {
/// Returns a future that resolves when the reaction is completely hidden.
Future hide() async {
await _showComplete;
await _hidePerformance.forward();
await _fade.forward();
}
/// Call listener whenever the visual appearance of the reaction changes
void addListener(Function listener) {
_showPerformance.addListener(listener);
_hidePerformance.addListener(listener);
_fade.addListener(listener);
}
final Paint _outerPaint = new Paint();
......
......@@ -24,13 +24,18 @@ abstract class RenderToggleable extends RenderConstrainedBox {
: _value = value,
_onChanged = onChanged,
super(additionalConstraints: new BoxConstraints.tight(size)) {
_performance = new AnimationPerformance()
..variable = _position
..duration = _kToggleDuration
..progress = _value ? 1.0 : 0.0
..addListener(markNeedsPaint);
_performance = new ValueAnimation<double>(
variable: new AnimatedValue<double>(0.0, end: 1.0, curve: easeIn, reverseCurve: easeOut),
duration: _kToggleDuration,
progress: _value ? 1.0 : 0.0
)..addListener(markNeedsPaint);
}
ValueAnimation<double> get performance => _performance;
ValueAnimation<double> _performance;
double get position => _performance.value;
void handleEvent(sky.Event event, BoxHitTestEntry entry) {
if (event.type == 'pointerdown')
_tap.addPointer(event);
......@@ -68,15 +73,7 @@ abstract class RenderToggleable extends RenderConstrainedBox {
ValueChanged get onChanged => _onChanged;
ValueChanged _onChanged;
void set onChanged(ValueChanged onChanged) {
_onChanged = onChanged;
}
AnimatedValue<double> get position => _position;
final AnimatedValue<double> _position =
new AnimatedValue<double>(0.0, end: 1.0, curve: easeIn, reverseCurve: easeOut);
AnimationPerformance get performance => _performance;
AnimationPerformance _performance;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment