From 3b62185f8a6d69ee4288408f8e2ef16e03374013 Mon Sep 17 00:00:00 2001 From: Hixie Date: Wed, 30 Sep 2015 13:47:14 -0700 Subject: [PATCH] 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. --- .../src/animation/animation_performance.dart | 50 +++++++------------ packages/flutter/lib/src/fn3/checkbox.dart | 10 ++-- packages/flutter/lib/src/fn3/ink_well.dart | 10 ++-- .../lib/src/fn3/progress_indicator.dart | 17 ++++--- packages/flutter/lib/src/fn3/switch.dart | 10 ++-- .../lib/src/painting/radial_reaction.dart | 27 +++++----- .../flutter/lib/src/rendering/toggleable.dart | 23 ++++----- 7 files changed, 66 insertions(+), 81 deletions(-) diff --git a/packages/flutter/lib/src/animation/animation_performance.dart b/packages/flutter/lib/src/animation/animation_performance.dart index 9bb46b9c77..9105498dc4 100644 --- a/packages/flutter/lib/src/animation/animation_performance.dart +++ b/packages/flutter/lib/src/animation/animation_performance.dart @@ -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 extends AnimationPerformance { - ValueAnimation({ AnimatedValue variable, Duration duration }) : - super(variable: variable, duration: duration); - - AnimatedValue get variable => _variable as AnimatedValue; - void set variable(AnimatedValue v) { _variable = v; } + ValueAnimation({ this.variable, Duration duration, double progress }) : + super(duration: duration, progress: progress); + AnimatedValue variable; T get value => variable.value; + + void didTick(double t) { + if (variable != null) + variable.setProgress(_curvedProgress, _curveDirection); + super.didTick(t); + } } diff --git a/packages/flutter/lib/src/fn3/checkbox.dart b/packages/flutter/lib/src/fn3/checkbox.dart index ba337bf68c..361ef86700 100644 --- a/packages/flutter/lib/src/fn3/checkbox.dart +++ b/packages/flutter/lib/src/fn3/checkbox.dart @@ -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); diff --git a/packages/flutter/lib/src/fn3/ink_well.dart b/packages/flutter/lib/src/fn3/ink_well.dart index 0429cd9601..531bb08cd5 100644 --- a/packages/flutter/lib/src/fn3/ink_well.dart +++ b/packages/flutter/lib/src/fn3/ink_well.dart @@ -30,11 +30,11 @@ class InkSplash { _radius = new AnimatedValue( _kSplashInitialSize, end: _targetRadius, curve: easeOut); - _performance = new AnimationPerformance() - ..variable = _radius - ..duration = new Duration(milliseconds: (_targetRadius / _kSplashUnconfirmedVelocity).floor()) - ..addListener(_handleRadiusChange) - ..play(); + _performance = new ValueAnimation( + variable: _radius, + duration: new Duration(milliseconds: (_targetRadius / _kSplashUnconfirmedVelocity).floor()) + )..addListener(_handleRadiusChange) + ..play(); } final int pointer; diff --git a/packages/flutter/lib/src/fn3/progress_indicator.dart b/packages/flutter/lib/src/fn3/progress_indicator.dart index 5c9eccee62..bbd2f8f3f9 100644 --- a/packages/flutter/lib/src/fn3/progress_indicator.dart +++ b/packages/flutter/lib/src/fn3/progress_indicator.dart @@ -35,11 +35,15 @@ abstract class ProgressIndicator extends StatefulComponent { } class ProgressIndicatorState extends State { + + ValueAnimation _performance; + void initState() { super.initState(); - _performance = new AnimationPerformance() - ..duration = const Duration(milliseconds: 1500) - ..variable = new AnimatedValue(0.0, end: 1.0, curve: ease); + _performance = new ValueAnimation( + variable: new AnimatedValue(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 { _performance.play(); } - AnimationPerformance _performance; - double get _performanceValue => (_performance.variable as AnimatedValue).value; - void _restartAnimation() { _performance.progress = 0.0; _performance.play(); @@ -57,13 +58,13 @@ class ProgressIndicatorState extends State { 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); } ); } diff --git a/packages/flutter/lib/src/fn3/switch.dart b/packages/flutter/lib/src/fn3/switch.dart index 5951091c32..ae58b3849b 100644 --- a/packages/flutter/lib/src/fn3/switch.dart +++ b/packages/flutter/lib/src/fn3/switch.dart @@ -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); } diff --git a/packages/flutter/lib/src/painting/radial_reaction.dart b/packages/flutter/lib/src/painting/radial_reaction.dart index 0e4aa0034c..c7997e4e5e 100644 --- a/packages/flutter/lib/src/painting/radial_reaction.dart +++ b/packages/flutter/lib/src/painting/radial_reaction.dart @@ -30,16 +30,16 @@ class RadialReaction { _outerOpacity = new AnimatedValue(0.0, end: _kMaxOpacity, curve: easeOut); _innerCenter = new AnimatedValue(startPosition, end: center, curve: easeOut); _innerRadius = new AnimatedValue(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( + 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 _fade; + ValueAnimation _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(); diff --git a/packages/flutter/lib/src/rendering/toggleable.dart b/packages/flutter/lib/src/rendering/toggleable.dart index 374136c6ef..ad9d7bc132 100644 --- a/packages/flutter/lib/src/rendering/toggleable.dart +++ b/packages/flutter/lib/src/rendering/toggleable.dart @@ -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( + variable: new AnimatedValue(0.0, end: 1.0, curve: easeIn, reverseCurve: easeOut), + duration: _kToggleDuration, + progress: _value ? 1.0 : 0.0 + )..addListener(markNeedsPaint); } + ValueAnimation get performance => _performance; + ValueAnimation _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 get position => _position; - final AnimatedValue _position = - new AnimatedValue(0.0, end: 1.0, curve: easeIn, reverseCurve: easeOut); - - AnimationPerformance get performance => _performance; - AnimationPerformance _performance; }