Commit 34a65dae authored by Adam Barth's avatar Adam Barth

Merge pull request #1311 from abarth/port_material

Move Scaffold over to using AnimationController
parents 386b2775 d25951c5
...@@ -12,10 +12,10 @@ class PageSelectorDemo extends StatelessComponent { ...@@ -12,10 +12,10 @@ class PageSelectorDemo extends StatelessComponent {
final ColorTween _previousColor = new ColorTween(begin: color, end: Colors.transparent); final ColorTween _previousColor = new ColorTween(begin: color, end: Colors.transparent);
final TabBarSelectionState selection = TabBarSelection.of(context); final TabBarSelectionState selection = TabBarSelection.of(context);
Animation animation = new CurvedAnimation(parent: selection.animation, curve: Curves.ease); CurvedAnimation animation = new CurvedAnimation(parent: selection.animation, curve: Curves.ease);
return new AnimationWatchingBuilder( return new AnimatedBuilder(
watchable: animation, animation: animation,
builder: (BuildContext context) { builder: (BuildContext context, Widget child) {
Color background = selection.value == iconName ? _selectedColor.end : _selectedColor.begin; Color background = selection.value == iconName ? _selectedColor.end : _selectedColor.begin;
if (selection.valueIsChanging) { if (selection.valueIsChanging) {
// Then the selection's performance is animating from previousValue to value. // Then the selection's performance is animating from previousValue to value.
......
...@@ -27,7 +27,7 @@ class _ProgressIndicatorDemoState extends State<ProgressIndicatorDemo> { ...@@ -27,7 +27,7 @@ class _ProgressIndicatorDemoState extends State<ProgressIndicatorDemo> {
}); });
} }
Animation animation; Animated<double> animation;
AnimationController controller; AnimationController controller;
void handleTap() { void handleTap() {
...@@ -47,7 +47,7 @@ class _ProgressIndicatorDemoState extends State<ProgressIndicatorDemo> { ...@@ -47,7 +47,7 @@ class _ProgressIndicatorDemoState extends State<ProgressIndicatorDemo> {
controller.play(direction); controller.play(direction);
} }
Widget buildIndicators(BuildContext context) { Widget buildIndicators(BuildContext context, Widget child) {
List<Widget> indicators = <Widget>[ List<Widget> indicators = <Widget>[
new SizedBox( new SizedBox(
width: 200.0, width: 200.0,
...@@ -55,19 +55,19 @@ class _ProgressIndicatorDemoState extends State<ProgressIndicatorDemo> { ...@@ -55,19 +55,19 @@ class _ProgressIndicatorDemoState extends State<ProgressIndicatorDemo> {
), ),
new LinearProgressIndicator(), new LinearProgressIndicator(),
new LinearProgressIndicator(), new LinearProgressIndicator(),
new LinearProgressIndicator(value: animation.progress), new LinearProgressIndicator(value: animation.value),
new CircularProgressIndicator(), new CircularProgressIndicator(),
new SizedBox( new SizedBox(
width: 20.0, width: 20.0,
height: 20.0, height: 20.0,
child: new CircularProgressIndicator(value: animation.progress) child: new CircularProgressIndicator(value: animation.value)
), ),
new SizedBox( new SizedBox(
width: 50.0, width: 50.0,
height: 30.0, height: 30.0,
child: new CircularProgressIndicator(value: animation.progress) child: new CircularProgressIndicator(value: animation.value)
), ),
new Text("${(animation.progress * 100.0).toStringAsFixed(1)}%" + (controller.isAnimating ? '' : ' (paused)')) new Text("${(animation.value * 100.0).toStringAsFixed(1)}%" + (controller.isAnimating ? '' : ' (paused)'))
]; ];
return new Column( return new Column(
children: indicators children: indicators
...@@ -87,8 +87,8 @@ class _ProgressIndicatorDemoState extends State<ProgressIndicatorDemo> { ...@@ -87,8 +87,8 @@ class _ProgressIndicatorDemoState extends State<ProgressIndicatorDemo> {
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
child: new Container( child: new Container(
padding: const EdgeDims.symmetric(vertical: 12.0, horizontal: 8.0), padding: const EdgeDims.symmetric(vertical: 12.0, horizontal: 8.0),
child: new AnimationWatchingBuilder( child: new AnimatedBuilder(
watchable: animation, animation: animation,
builder: buildIndicators builder: buildIndicators
) )
) )
......
...@@ -33,15 +33,15 @@ class CardTransition extends StatelessComponent { ...@@ -33,15 +33,15 @@ class CardTransition extends StatelessComponent {
}); });
final Widget child; final Widget child;
final Animation animation; final Animated<double> animation;
final Evaluatable<double> x; final Evaluatable<double> x;
final Evaluatable<double> opacity; final Evaluatable<double> opacity;
final Evaluatable<double> scale; final Evaluatable<double> scale;
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new AnimationWatchingBuilder( return new AnimatedBuilder(
watchable: animation, animation: animation,
builder: (BuildContext context) { builder: (BuildContext context, Widget child) {
double currentScale = scale.evaluate(animation); double currentScale = scale.evaluate(animation);
Matrix4 transform = new Matrix4.identity() Matrix4 transform = new Matrix4.identity()
..translate(x.evaluate(animation)) ..translate(x.evaluate(animation))
...@@ -53,7 +53,8 @@ class CardTransition extends StatelessComponent { ...@@ -53,7 +53,8 @@ class CardTransition extends StatelessComponent {
child: child child: child
) )
); );
} },
child: child
); );
} }
} }
...@@ -62,7 +63,7 @@ class SmoothBlockState extends State<SmoothBlock> { ...@@ -62,7 +63,7 @@ class SmoothBlockState extends State<SmoothBlock> {
double _height = 100.0; double _height = 100.0;
Widget _handleEnter(Animation animation, Widget child) { Widget _handleEnter(Animated<double> animation, Widget child) {
return new CardTransition( return new CardTransition(
x: new Tween<double>(begin: -200.0, end: 0.0), x: new Tween<double>(begin: -200.0, end: 0.0),
opacity: new Tween<double>(begin: 0.0, end: 1.0), opacity: new Tween<double>(begin: 0.0, end: 1.0),
...@@ -72,7 +73,7 @@ class SmoothBlockState extends State<SmoothBlock> { ...@@ -72,7 +73,7 @@ class SmoothBlockState extends State<SmoothBlock> {
); );
} }
Widget _handleExit(Animation animation, Widget child) { Widget _handleExit(Animated<double> animation, Widget child) {
return new CardTransition( return new CardTransition(
x: new Tween<double>(begin: 0.0, end: 200.0), x: new Tween<double>(begin: 0.0, end: 200.0),
opacity: new Tween<double>(begin: 1.0, end: 0.0), opacity: new Tween<double>(begin: 1.0, end: 0.0),
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
library animation; library animation;
export 'src/animation/animated_value.dart'; export 'src/animation/animated_value.dart';
export 'src/animation/animations.dart';
export 'src/animation/clamped_simulation.dart'; export 'src/animation/clamped_simulation.dart';
export 'src/animation/curves.dart'; export 'src/animation/curves.dart';
export 'src/animation/forces.dart'; export 'src/animation/forces.dart';
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' show VoidCallback;
import 'animated_value.dart';
import 'listener_helpers.dart';
import 'tween.dart';
class AlwaysCompleteAnimation extends Animated<double> {
const AlwaysCompleteAnimation();
// this performance never changes state
void addListener(VoidCallback listener) { }
void removeListener(VoidCallback listener) { }
void addStatusListener(PerformanceStatusListener listener) { }
void removeStatusListener(PerformanceStatusListener listener) { }
PerformanceStatus get status => PerformanceStatus.completed;
AnimationDirection get direction => AnimationDirection.forward;
double get value => 1.0;
}
const AlwaysCompleteAnimation kAlwaysCompleteAnimation = const AlwaysCompleteAnimation();
class AlwaysDismissedAnimation extends Animated<double> {
const AlwaysDismissedAnimation();
// this performance never changes state
void addListener(VoidCallback listener) { }
void removeListener(VoidCallback listener) { }
void addStatusListener(PerformanceStatusListener listener) { }
void removeStatusListener(PerformanceStatusListener listener) { }
PerformanceStatus get status => PerformanceStatus.dismissed;
AnimationDirection get direction => AnimationDirection.forward;
double get value => 0.0;
}
const AlwaysDismissedAnimation kAlwaysDismissedAnimation = const AlwaysDismissedAnimation();
class ProxyAnimation extends Animated<double>
with LazyListenerMixin, LocalPerformanceListenersMixin, LocalPerformanceStatusListenersMixin {
ProxyAnimation([Animated<double> animation]) {
_masterAnimation = animation;
if (_masterAnimation == null) {
_status = PerformanceStatus.dismissed;
_direction = AnimationDirection.forward;
_value = 0.0;
}
}
PerformanceStatus _status;
AnimationDirection _direction;
double _value;
Animated<double> get masterAnimation => _masterAnimation;
Animated<double> _masterAnimation;
void set masterAnimation(Animated<double> value) {
if (value == _masterAnimation)
return;
if (_masterAnimation != null) {
_status = _masterAnimation.status;
_direction = _masterAnimation.direction;
_value = _masterAnimation.value;
if (isListening)
didStopListening();
}
_masterAnimation = value;
if (_masterAnimation != null) {
if (isListening)
didStartListening();
if (_value != _masterAnimation.value)
notifyListeners();
if (_status != _masterAnimation.status)
notifyStatusListeners(_masterAnimation.status);
_status = null;
_direction = null;
_value = null;
}
}
void didStartListening() {
if (_masterAnimation != null) {
_masterAnimation.addListener(notifyListeners);
_masterAnimation.addStatusListener(notifyStatusListeners);
}
}
void didStopListening() {
if (_masterAnimation != null) {
_masterAnimation.removeListener(notifyListeners);
_masterAnimation.removeStatusListener(notifyStatusListeners);
}
}
PerformanceStatus get status => _masterAnimation != null ? _masterAnimation.status : _status;
AnimationDirection get direction => _masterAnimation != null ? _masterAnimation.direction : _direction;
double get value => _masterAnimation != null ? _masterAnimation.value : _value;
}
class ReverseAnimation extends Animated<double>
with LazyListenerMixin, LocalPerformanceStatusListenersMixin {
ReverseAnimation(this.masterAnimation);
final Animated<double> masterAnimation;
void addListener(VoidCallback listener) {
didRegisterListener();
masterAnimation.addListener(listener);
}
void removeListener(VoidCallback listener) {
masterAnimation.removeListener(listener);
didUnregisterListener();
}
void didStartListening() {
masterAnimation.addStatusListener(_statusChangeHandler);
}
void didStopListening() {
masterAnimation.removeStatusListener(_statusChangeHandler);
}
void _statusChangeHandler(PerformanceStatus status) {
notifyStatusListeners(_reverseStatus(status));
}
PerformanceStatus get status => _reverseStatus(masterAnimation.status);
AnimationDirection get direction => _reverseDirection(masterAnimation.direction);
double get value => 1.0 - masterAnimation.value;
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;
}
}
}
enum _TrainHoppingMode { minimize, maximize }
/// This animation starts by proxying one animation, but can be given a
/// second animation. When their times cross (either because the second is
/// going in the opposite direction, or because the one overtakes the other),
/// the animation hops over to proxying the second animation, and the second
/// animation becomes the new "first" performance.
///
/// Since this object must track the two animations even when it has no
/// listeners of its own, instead of shutting down when all its listeners are
/// removed, it exposes a [dispose()] method. Call this method to shut this
/// object down.
class TrainHoppingAnimation extends Animated<double>
with EagerListenerMixin, LocalPerformanceListenersMixin, LocalPerformanceStatusListenersMixin {
TrainHoppingAnimation(this._currentTrain, this._nextTrain, { this.onSwitchedTrain }) {
assert(_currentTrain != null);
if (_nextTrain != null) {
if (_currentTrain.value > _nextTrain.value) {
_mode = _TrainHoppingMode.maximize;
} else {
_mode = _TrainHoppingMode.minimize;
if (_currentTrain.value == _nextTrain.value) {
_currentTrain = _nextTrain;
_nextTrain = null;
}
}
}
_currentTrain.addStatusListener(_statusChangeHandler);
_currentTrain.addListener(_valueChangeHandler);
if (_nextTrain != null)
_nextTrain.addListener(_valueChangeHandler);
assert(_mode != null);
}
Animated<double> get currentTrain => _currentTrain;
Animated<double> _currentTrain;
Animated<double> _nextTrain;
_TrainHoppingMode _mode;
VoidCallback onSwitchedTrain;
PerformanceStatus _lastStatus;
void _statusChangeHandler(PerformanceStatus status) {
assert(_currentTrain != null);
if (status != _lastStatus) {
notifyListeners();
_lastStatus = status;
}
assert(_lastStatus != null);
}
PerformanceStatus get status => _currentTrain.status;
AnimationDirection get direction => _currentTrain.direction;
double _lastValue;
void _valueChangeHandler() {
assert(_currentTrain != null);
bool hop = false;
if (_nextTrain != null) {
switch (_mode) {
case _TrainHoppingMode.minimize:
hop = _nextTrain.value <= _currentTrain.value;
break;
case _TrainHoppingMode.maximize:
hop = _nextTrain.value >= _currentTrain.value;
break;
}
if (hop) {
_currentTrain.removeStatusListener(_statusChangeHandler);
_currentTrain.removeListener(_valueChangeHandler);
_currentTrain = _nextTrain;
_nextTrain.addListener(_valueChangeHandler);
_statusChangeHandler(_nextTrain.status);
}
}
double newValue = value;
if (newValue != _lastValue) {
notifyListeners();
_lastValue = newValue;
}
assert(_lastValue != null);
if (hop && onSwitchedTrain != null)
onSwitchedTrain();
}
double get value => _currentTrain.value;
/// Frees all the resources used by this performance.
/// After this is called, this object is no longer usable.
void dispose() {
assert(_currentTrain != null);
_currentTrain.removeStatusListener(_statusChangeHandler);
_currentTrain.removeListener(_valueChangeHandler);
_currentTrain = null;
if (_nextTrain != null) {
_nextTrain.removeListener(_valueChangeHandler);
_nextTrain = null;
}
}
}
...@@ -13,16 +13,16 @@ import 'forces.dart'; ...@@ -13,16 +13,16 @@ import 'forces.dart';
import 'listener_helpers.dart'; import 'listener_helpers.dart';
import 'simulation_stepper.dart'; import 'simulation_stepper.dart';
abstract class Watchable { abstract class Animated<T> {
const Watchable(); const Animated();
/// Calls the listener every time the progress of the performance changes. /// Calls the listener every time the value of the animation changes.
void addListener(VoidCallback listener); void addListener(VoidCallback listener);
/// Stop calling the listener every time the progress of the performance changes. /// Stop calling the listener every time the value of the animation changes.
void removeListener(VoidCallback listener); void removeListener(VoidCallback listener);
/// Calls listener every time the status of the performance changes. /// Calls listener every time the status of the animation changes.
void addStatusListener(PerformanceStatusListener listener); void addStatusListener(PerformanceStatusListener listener);
/// Stops calling the listener every time the status of the performance changes. /// Stops calling the listener every time the status of the animation changes.
void removeStatusListener(PerformanceStatusListener listener); void removeStatusListener(PerformanceStatusListener listener);
/// The current status of this animation. /// The current status of this animation.
...@@ -31,6 +31,9 @@ abstract class Watchable { ...@@ -31,6 +31,9 @@ abstract class Watchable {
/// The current direction of the animation. /// The current direction of the animation.
AnimationDirection get direction; AnimationDirection get direction;
/// The current value of the animation.
T get value;
/// Whether this animation is stopped at the beginning. /// Whether this animation is stopped at the beginning.
bool get isDismissed => status == PerformanceStatus.dismissed; bool get isDismissed => status == PerformanceStatus.dismissed;
...@@ -77,8 +80,8 @@ abstract class Watchable { ...@@ -77,8 +80,8 @@ abstract class Watchable {
} }
} }
abstract class ProxyWatchableMixin implements Watchable { abstract class ProxyAnimatedMixin {
Watchable get parent; Animated<double> get parent;
void addListener(VoidCallback listener) => parent.addListener(listener); void addListener(VoidCallback listener) => parent.addListener(listener);
void removeListener(VoidCallback listener) => parent.removeListener(listener); void removeListener(VoidCallback listener) => parent.removeListener(listener);
...@@ -92,37 +95,30 @@ abstract class ProxyWatchableMixin implements Watchable { ...@@ -92,37 +95,30 @@ abstract class ProxyWatchableMixin implements Watchable {
abstract class Evaluatable<T> { abstract class Evaluatable<T> {
const Evaluatable(); const Evaluatable();
T evaluate(Animation animation); T evaluate(Animated<double> animation);
WatchableValue<T> watch(Animation parent) { Animated<T> animate(Animated<double> parent) {
return new WatchableValue<T>(parent: parent, evaluatable: this); return new _AnimatedEvaluation<T>(parent, this);
} }
} }
class WatchableValue<T> extends Watchable with ProxyWatchableMixin { class _AnimatedEvaluation<T> extends Animated<T> with ProxyAnimatedMixin {
WatchableValue({ this.parent, this.evaluatable }); _AnimatedEvaluation(this.parent, this._evaluatable);
final Animation parent;
final Evaluatable<T> evaluatable;
T get value => evaluatable.evaluate(parent); /// The animation from which this value is derived.
} final Animated<double> parent;
abstract class Animation extends Watchable { final Evaluatable<T> _evaluatable;
/// The current progress of this animation (a value from 0.0 to 1.0).
double get progress;
String toStringDetails() { T get value => _evaluatable.evaluate(parent);
return '${super.toStringDetails()} ${progress.toStringAsFixed(3)}';
}
} }
class AnimationController extends Animation class AnimationController extends Animated<double>
with EagerListenerMixin, LocalPerformanceListenersMixin, LocalPerformanceStatusListenersMixin { with EagerListenerMixin, LocalPerformanceListenersMixin, LocalPerformanceStatusListenersMixin {
AnimationController({ this.duration, double progress, this.debugLabel }) { AnimationController({ this.duration, double value, this.debugLabel }) {
_timeline = new SimulationStepper(_tick); _timeline = new SimulationStepper(_tick);
if (progress != null) if (value != null)
_timeline.value = progress.clamp(0.0, 1.0); _timeline.value = value.clamp(0.0, 1.0);
} }
/// A label that is used in the [toString] output. Intended to aid with /// A label that is used in the [toString] output. Intended to aid with
...@@ -132,7 +128,7 @@ class AnimationController extends Animation ...@@ -132,7 +128,7 @@ class AnimationController extends Animation
/// Returns a [Animation] for this performance, /// Returns a [Animation] for this performance,
/// so that a pointer to this object can be passed around without /// so that a pointer to this object can be passed around without
/// allowing users of that pointer to mutate the Performance state. /// allowing users of that pointer to mutate the Performance state.
Animation get view => this; Animated<double> get view => this;
/// The length of time this performance should last. /// The length of time this performance should last.
Duration duration; Duration duration;
...@@ -144,8 +140,8 @@ class AnimationController extends Animation ...@@ -144,8 +140,8 @@ class AnimationController extends Animation
/// The progress of this performance along the timeline. /// The progress of this performance along the timeline.
/// ///
/// Note: Setting this value stops the current animation. /// Note: Setting this value stops the current animation.
double get progress => _timeline.value.clamp(0.0, 1.0); double get value => _timeline.value.clamp(0.0, 1.0);
void set progress(double t) { void set value(double t) {
stop(); stop();
_timeline.value = t.clamp(0.0, 1.0); _timeline.value = t.clamp(0.0, 1.0);
_checkStatusChanged(); _checkStatusChanged();
...@@ -155,9 +151,9 @@ class AnimationController extends Animation ...@@ -155,9 +151,9 @@ class AnimationController extends Animation
bool get isAnimating => _timeline.isAnimating; bool get isAnimating => _timeline.isAnimating;
PerformanceStatus get status { PerformanceStatus get status {
if (!isAnimating && progress == 1.0) if (!isAnimating && value == 1.0)
return PerformanceStatus.completed; return PerformanceStatus.completed;
if (!isAnimating && progress == 0.0) if (!isAnimating && value == 0.0)
return PerformanceStatus.dismissed; return PerformanceStatus.dismissed;
return _direction == AnimationDirection.forward ? return _direction == AnimationDirection.forward ?
PerformanceStatus.forward : PerformanceStatus.forward :
...@@ -200,7 +196,7 @@ class AnimationController extends Animation ...@@ -200,7 +196,7 @@ class AnimationController extends Animation
Future fling({double velocity: 1.0, Force force}) { Future fling({double velocity: 1.0, Force force}) {
force ??= kDefaultSpringForce; force ??= kDefaultSpringForce;
_direction = velocity < 0.0 ? AnimationDirection.reverse : AnimationDirection.forward; _direction = velocity < 0.0 ? AnimationDirection.reverse : AnimationDirection.forward;
return _timeline.animateWith(force.release(progress, velocity)); return _timeline.animateWith(force.release(value, velocity));
} }
/// Starts running this animation in the forward direction, and /// Starts running this animation in the forward direction, and
...@@ -234,7 +230,7 @@ class AnimationController extends Animation ...@@ -234,7 +230,7 @@ class AnimationController extends Animation
String toStringDetails() { String toStringDetails() {
String paused = _timeline.isAnimating ? '' : '; paused'; String paused = _timeline.isAnimating ? '' : '; paused';
String label = debugLabel == null ? '' : '; for $debugLabel'; String label = debugLabel == null ? '' : '; for $debugLabel';
String more = super.toStringDetails(); String more = '${super.toStringDetails()} ${value.toStringAsFixed(3)}';
return '$more$paused$label'; return '$more$paused$label';
} }
} }
...@@ -261,14 +257,18 @@ class _RepeatingSimulation extends Simulation { ...@@ -261,14 +257,18 @@ class _RepeatingSimulation extends Simulation {
bool isDone(double timeInSeconds) => false; bool isDone(double timeInSeconds) => false;
} }
class CurvedAnimation extends Animation with ProxyWatchableMixin { class CurvedAnimation extends Animated<double> with ProxyAnimatedMixin {
CurvedAnimation({ this.parent, this.curve, this.reverseCurve }) { CurvedAnimation({
this.parent,
this.curve: Curves.linear,
this.reverseCurve
}) {
assert(parent != null); assert(parent != null);
assert(curve != null); assert(curve != null);
parent.addStatusListener(_handleStatusChanged); parent.addStatusListener(_handleStatusChanged);
} }
final Animation parent; final Animated<double> parent;
/// The curve to use in the forward direction. /// The curve to use in the forward direction.
Curve curve; Curve curve;
...@@ -300,11 +300,11 @@ class CurvedAnimation extends Animation with ProxyWatchableMixin { ...@@ -300,11 +300,11 @@ class CurvedAnimation extends Animation with ProxyWatchableMixin {
} }
} }
double get progress { double get value {
final bool useForwardCurve = reverseCurve == null || (_curveDirection ?? parent.direction) == AnimationDirection.forward; final bool useForwardCurve = reverseCurve == null || (_curveDirection ?? parent.direction) == AnimationDirection.forward;
Curve activeCurve = useForwardCurve ? curve : reverseCurve; Curve activeCurve = useForwardCurve ? curve : reverseCurve;
double t = parent.progress; double t = parent.value;
if (activeCurve == null) if (activeCurve == null)
return t; return t;
if (t == 0.0 || t == 1.0) { if (t == 0.0 || t == 1.0) {
...@@ -327,10 +327,10 @@ class Tween<T extends dynamic> extends Evaluatable<T> { ...@@ -327,10 +327,10 @@ class Tween<T extends dynamic> extends Evaluatable<T> {
/// Returns the value this variable has at the given animation clock value. /// Returns the value this variable has at the given animation clock value.
T lerp(double t) => begin + (end - begin) * t; T lerp(double t) => begin + (end - begin) * t;
T evaluate(Animation animation) { T evaluate(Animated<double> animation) {
if (end == null) if (end == null)
return begin; return begin;
double t = animation.progress; double t = animation.value;
if (t == 0.0) if (t == 0.0)
return begin; return begin;
if (t == 1.0) if (t == 1.0)
...@@ -377,3 +377,18 @@ class IntTween extends Tween<int> { ...@@ -377,3 +377,18 @@ class IntTween extends Tween<int> {
// the begin and end types by a double, and int * double returns a double. // the begin and end types by a double, and int * double returns a double.
int lerp(double t) => (begin + (end - begin) * t).round(); int lerp(double t) => (begin + (end - begin) * t).round();
} }
class CurveTween extends Evaluatable<double> {
CurveTween({ this.curve });
Curve curve;
double evaluate(Animated<double> animation) {
double t = animation.value;
if (t == 0.0 || t == 1.0) {
assert(curve.transform(t).round() == t);
return t;
}
return curve.transform(t);
}
}
...@@ -21,24 +21,24 @@ const Color _kBarrierColor = Colors.black54; ...@@ -21,24 +21,24 @@ const Color _kBarrierColor = Colors.black54;
class BottomSheet extends StatefulComponent { class BottomSheet extends StatefulComponent {
BottomSheet({ BottomSheet({
Key key, Key key,
this.performance, this.animationController,
this.onClosing, this.onClosing,
this.builder this.builder
}) : super(key: key) { }) : super(key: key) {
assert(onClosing != null); assert(onClosing != null);
} }
/// The performance that controls the bottom sheet's position. The BottomSheet /// The animation that controls the bottom sheet's position. The BottomSheet
/// widget will manipulate the position of this performance, it is not just a /// widget will manipulate the position of this animation, it is not just a
/// passive observer. /// passive observer.
final Performance performance; final AnimationController animationController;
final VoidCallback onClosing; final VoidCallback onClosing;
final WidgetBuilder builder; final WidgetBuilder builder;
_BottomSheetState createState() => new _BottomSheetState(); _BottomSheetState createState() => new _BottomSheetState();
static Performance createPerformanceController() { static AnimationController createAnimationController() {
return new Performance( return new AnimationController(
duration: _kBottomSheetDuration, duration: _kBottomSheetDuration,
debugLabel: 'BottomSheet' debugLabel: 'BottomSheet'
); );
...@@ -54,12 +54,12 @@ class _BottomSheetState extends State<BottomSheet> { ...@@ -54,12 +54,12 @@ class _BottomSheetState extends State<BottomSheet> {
return renderBox.size.height; return renderBox.size.height;
} }
bool get _dismissUnderway => config.performance.direction == AnimationDirection.reverse; bool get _dismissUnderway => config.animationController.direction == AnimationDirection.reverse;
void _handleDragUpdate(double delta) { void _handleDragUpdate(double delta) {
if (_dismissUnderway) if (_dismissUnderway)
return; return;
config.performance.progress -= delta / (_childHeight ?? delta); config.animationController.value -= delta / (_childHeight ?? delta);
} }
void _handleDragEnd(Offset velocity) { void _handleDragEnd(Offset velocity) {
...@@ -67,14 +67,14 @@ class _BottomSheetState extends State<BottomSheet> { ...@@ -67,14 +67,14 @@ class _BottomSheetState extends State<BottomSheet> {
return; return;
if (velocity.dy > _kMinFlingVelocity) { if (velocity.dy > _kMinFlingVelocity) {
double flingVelocity = -velocity.dy / _childHeight; double flingVelocity = -velocity.dy / _childHeight;
config.performance.fling(velocity: flingVelocity); config.animationController.fling(velocity: flingVelocity);
if (flingVelocity < 0.0) if (flingVelocity < 0.0)
config.onClosing(); config.onClosing();
} else if (config.performance.progress < _kCloseProgressThreshold) { } else if (config.animationController.value < _kCloseProgressThreshold) {
config.performance.fling(velocity: -1.0); config.animationController.fling(velocity: -1.0);
config.onClosing(); config.onClosing();
} else { } else {
config.performance.forward(); config.animationController.forward();
} }
} }
...@@ -132,14 +132,14 @@ class _ModalBottomSheetState extends State<_ModalBottomSheet> { ...@@ -132,14 +132,14 @@ class _ModalBottomSheetState extends State<_ModalBottomSheet> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new GestureDetector( return new GestureDetector(
onTap: () => Navigator.pop(context), onTap: () => Navigator.pop(context),
child: new BuilderTransition( child: new AnimatedBuilder(
performance: config.route.performance, animation: config.route.animation,
builder: (BuildContext context) { builder: (BuildContext context, Widget child) {
return new ClipRect( return new ClipRect(
child: new CustomOneChildLayout( child: new CustomOneChildLayout(
delegate: new _ModalBottomSheetLayout(config.route.performance.progress), delegate: new _ModalBottomSheetLayout(config.route.animation.value),
child: new BottomSheet( child: new BottomSheet(
performance: config.route.performance, animationController: config.route.animation,
onClosing: () => Navigator.pop(context), onClosing: () => Navigator.pop(context),
builder: config.route.builder builder: config.route.builder
) )
...@@ -163,11 +163,11 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> { ...@@ -163,11 +163,11 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
bool get barrierDismissable => true; bool get barrierDismissable => true;
Color get barrierColor => Colors.black54; Color get barrierColor => Colors.black54;
Performance createPerformanceController() { AnimationController createAnimationController() {
return BottomSheet.createPerformanceController(); return BottomSheet.createAnimationController();
} }
Widget buildPage(BuildContext context, PerformanceView performance, PerformanceView forwardPerformance) { Widget buildPage(BuildContext context, Animated<double> animation, Animated<double> forwardAnimation) {
return new _ModalBottomSheet(route: this); return new _ModalBottomSheet(route: this);
} }
} }
......
...@@ -128,14 +128,16 @@ class _DialogRoute<T> extends PopupRoute<T> { ...@@ -128,14 +128,16 @@ class _DialogRoute<T> extends PopupRoute<T> {
bool get barrierDismissable => true; bool get barrierDismissable => true;
Color get barrierColor => Colors.black54; Color get barrierColor => Colors.black54;
Widget buildPage(BuildContext context, PerformanceView performance, PerformanceView forwardPerformance) { Widget buildPage(BuildContext context, Animated<double> animation, Animated<double> forwardAnimation) {
return child; return child;
} }
Widget buildTransitions(BuildContext context, PerformanceView performance, PerformanceView forwardPerformance, Widget child) { Widget buildTransitions(BuildContext context, Animated<double> animation, Animated<double> forwardAnimation, Widget child) {
return new FadeTransition( return new FadeTransition(
performance: performance, opacity: new CurvedAnimation(
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: Curves.easeOut), parent: animation,
curve: Curves.easeOut
),
child: child child: child
); );
} }
......
...@@ -62,7 +62,7 @@ class _DropDownMenu<T> extends StatusTransitionComponent { ...@@ -62,7 +62,7 @@ class _DropDownMenu<T> extends StatusTransitionComponent {
_DropDownMenu({ _DropDownMenu({
Key key, Key key,
_DropDownRoute<T> route _DropDownRoute<T> route
}) : route = route, super(key: key, performance: route.performance); }) : route = route, super(key: key, animation: route.animation);
final _DropDownRoute<T> route; final _DropDownRoute<T> route;
...@@ -79,16 +79,15 @@ class _DropDownMenu<T> extends StatusTransitionComponent { ...@@ -79,16 +79,15 @@ class _DropDownMenu<T> extends StatusTransitionComponent {
final double unit = 0.5 / (route.items.length + 1.5); final double unit = 0.5 / (route.items.length + 1.5);
final List<Widget> children = <Widget>[]; final List<Widget> children = <Widget>[];
for (int itemIndex = 0; itemIndex < route.items.length; ++itemIndex) { for (int itemIndex = 0; itemIndex < route.items.length; ++itemIndex) {
AnimatedValue<double> opacity; CurvedAnimation opacity;
if (itemIndex == route.selectedIndex) { if (itemIndex == route.selectedIndex) {
opacity = new AnimatedValue<double>(0.0, end: 1.0, curve: const Interval(0.0, 0.001), reverseCurve: const Interval(0.75, 1.0)); opacity = new CurvedAnimation(parent: route.animation, curve: const Interval(0.0, 0.001), reverseCurve: const Interval(0.75, 1.0));
} else { } else {
final double start = (0.5 + (itemIndex + 1) * unit).clamp(0.0, 1.0); final double start = (0.5 + (itemIndex + 1) * unit).clamp(0.0, 1.0);
final double end = (start + 1.5 * unit).clamp(0.0, 1.0); final double end = (start + 1.5 * unit).clamp(0.0, 1.0);
opacity = new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(start, end), reverseCurve: const Interval(0.75, 1.0)); opacity = new CurvedAnimation(parent: route.animation, curve: new Interval(start, end), reverseCurve: const Interval(0.75, 1.0));
} }
children.add(new FadeTransition( children.add(new FadeTransition(
performance: route.performance,
opacity: opacity, opacity: opacity,
child: new InkWell( child: new InkWell(
child: new Container( child: new Container(
...@@ -103,44 +102,48 @@ class _DropDownMenu<T> extends StatusTransitionComponent { ...@@ -103,44 +102,48 @@ class _DropDownMenu<T> extends StatusTransitionComponent {
)); ));
} }
final AnimatedValue<double> menuOpacity = new AnimatedValue<double>(0.0, final CurvedAnimation opacity = new CurvedAnimation(
end: 1.0, parent: route.animation,
curve: const Interval(0.0, 0.25), curve: const Interval(0.0, 0.25),
reverseCurve: const Interval(0.75, 1.0) reverseCurve: const Interval(0.75, 1.0)
); );
final AnimatedValue<double> menuTop = new AnimatedValue<double>(route.rect.top, final CurvedAnimation resize = new CurvedAnimation(
end: route.rect.top - route.selectedIndex * route.rect.height, parent: route.animation,
curve: const Interval(0.25, 0.5), curve: const Interval(0.25, 0.5),
reverseCurve: const Interval(0.0, 0.001) reverseCurve: const Interval(0.0, 0.001)
); );
final AnimatedValue<double> menuBottom = new AnimatedValue<double>(route.rect.bottom,
end: menuTop.end + route.items.length * route.rect.height, final Tween<double> menuTop = new Tween<double>(
curve: const Interval(0.25, 0.5), begin: route.rect.top,
reverseCurve: const Interval(0.0, 0.001) end: route.rect.top - route.selectedIndex * route.rect.height
);
final Tween<double> menuBottom = new Tween<double>(
begin: route.rect.bottom,
end: menuTop.end + route.items.length * route.rect.height
); );
Widget child = new Material(
type: MaterialType.transparency,
child: new Block(children)
);
return new FadeTransition( return new FadeTransition(
performance: route.performance, opacity: opacity,
opacity: menuOpacity, child: new AnimatedBuilder(
child: new BuilderTransition( animation: resize,
performance: route.performance, builder: (BuildContext context, Widget child) {
variables: <AnimatedValue<double>>[menuTop, menuBottom],
builder: (BuildContext context) {
return new CustomPaint( return new CustomPaint(
painter: new _DropDownMenuPainter( painter: new _DropDownMenuPainter(
color: Theme.of(context).canvasColor, color: Theme.of(context).canvasColor,
elevation: route.elevation, elevation: route.elevation,
menuTop: menuTop.value, menuTop: menuTop.evaluate(resize),
menuBottom: menuBottom.value, menuBottom: menuBottom.evaluate(resize),
renderBox: context.findRenderObject() renderBox: context.findRenderObject()
), ),
child: new Material( child: child
type: MaterialType.transparency,
child: new Block(children)
)
); );
} },
child: child
) )
); );
} }
...@@ -190,7 +193,7 @@ class _DropDownRoute<T> extends PopupRoute<_DropDownRouteResult<T>> { ...@@ -190,7 +193,7 @@ class _DropDownRoute<T> extends PopupRoute<_DropDownRouteResult<T>> {
); );
} }
Widget buildPage(BuildContext context, PerformanceView performance, PerformanceView forwardPerformance) { Widget buildPage(BuildContext context, Animated<double> animation, Animated<double> forwardAnimation) {
return new _DropDownMenu(route: this); return new _DropDownMenu(route: this);
} }
} }
......
...@@ -40,20 +40,29 @@ class FloatingActionButton extends StatefulComponent { ...@@ -40,20 +40,29 @@ class FloatingActionButton extends StatefulComponent {
} }
class _FloatingActionButtonState extends State<FloatingActionButton> { class _FloatingActionButtonState extends State<FloatingActionButton> {
final Performance _childSegue = new Performance(duration: _kChildSegue); Animated<double> _childSegue;
AnimationController _childSegueController;
void initState() { void initState() {
super.initState(); super.initState();
_childSegue.play(); _childSegueController = new AnimationController(duration: _kChildSegue)
..forward();
_childSegue = new Tween<double>(
begin: -0.125,
end: 0.0
).animate(new CurvedAnimation(
parent: _childSegueController,
curve: _kChildSegueInterval
));
} }
void didUpdateConfig(FloatingActionButton oldConfig) { void didUpdateConfig(FloatingActionButton oldConfig) {
super.didUpdateConfig(oldConfig); super.didUpdateConfig(oldConfig);
if (Widget.canUpdate(oldConfig.child, config.child) && config.backgroundColor == oldConfig.backgroundColor) if (Widget.canUpdate(oldConfig.child, config.child) && config.backgroundColor == oldConfig.backgroundColor)
return; return;
_childSegue _childSegueController
..progress = 0.0 ..value = 0.0
..play(); ..forward();
} }
bool _highlight = false; bool _highlight = false;
...@@ -87,8 +96,7 @@ class _FloatingActionButtonState extends State<FloatingActionButton> { ...@@ -87,8 +96,7 @@ class _FloatingActionButtonState extends State<FloatingActionButton> {
child: new IconTheme( child: new IconTheme(
data: new IconThemeData(color: iconThemeColor), data: new IconThemeData(color: iconThemeColor),
child: new RotationTransition( child: new RotationTransition(
performance: _childSegue, turns: _childSegue,
turns: new AnimatedValue<double>(-0.125, end: 0.0, curve: _kChildSegueInterval),
child: config.child child: config.child
) )
) )
......
...@@ -7,31 +7,32 @@ import 'dart:async'; ...@@ -7,31 +7,32 @@ import 'dart:async';
import 'package:flutter/animation.dart'; import 'package:flutter/animation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
class _MaterialPageTransition extends TransitionWithChild { class _MaterialPageTransition extends AnimatedComponent {
_MaterialPageTransition({ _MaterialPageTransition({
Key key, Key key,
PerformanceView performance, Animated<double> animation,
Widget child this.child
}) : super(key: key, }) : super(
performance: performance, key: key,
child: child); animation: new CurvedAnimation(parent: animation, curve: Curves.easeOut)
);
final AnimatedValue<Point> _position = final Widget child;
new AnimatedValue<Point>(const Point(0.0, 75.0), end: Point.origin, curve: Curves.easeOut);
final AnimatedValue<double> _opacity = final Tween<Point> _position = new Tween<Point>(
new AnimatedValue<double>(0.0, end: 1.0, curve: Curves.easeOut); begin: const Point(0.0, 75.0),
end: Point.origin
);
Widget buildWithChild(BuildContext context, Widget child) { Widget build(BuildContext context) {
performance.updateVariable(_position); Point position = _position.evaluate(animation);
performance.updateVariable(_opacity);
Matrix4 transform = new Matrix4.identity() Matrix4 transform = new Matrix4.identity()
..translate(_position.value.x, _position.value.y); ..translate(position.x, position.y);
return new Transform( return new Transform(
transform: transform, transform: transform,
// TODO(ianh): tell the transform to be un-transformed for hit testing // TODO(ianh): tell the transform to be un-transformed for hit testing
child: new Opacity( child: new Opacity(
opacity: _opacity.value, opacity: animation.value,
child: child child: child
) )
); );
...@@ -56,7 +57,7 @@ class MaterialPageRoute<T> extends PageRoute<T> { ...@@ -56,7 +57,7 @@ class MaterialPageRoute<T> extends PageRoute<T> {
Color get barrierColor => null; Color get barrierColor => null;
bool canTransitionFrom(TransitionRoute nextRoute) => false; bool canTransitionFrom(TransitionRoute nextRoute) => false;
Widget buildPage(BuildContext context, PerformanceView performance, PerformanceView forwardPerformance) { Widget buildPage(BuildContext context, Animated<double> animation, Animated<double> forwardAnimation) {
Widget result = builder(context); Widget result = builder(context);
assert(() { assert(() {
if (result == null) if (result == null)
...@@ -67,9 +68,9 @@ class MaterialPageRoute<T> extends PageRoute<T> { ...@@ -67,9 +68,9 @@ class MaterialPageRoute<T> extends PageRoute<T> {
return result; return result;
} }
Widget buildTransitions(BuildContext context, PerformanceView performance, PerformanceView forwardPerformance, Widget child) { Widget buildTransitions(BuildContext context, Animated<double> animation, Animated<double> forwardAnimation, Widget child) {
return new _MaterialPageTransition( return new _MaterialPageTransition(
performance: performance, animation: animation,
child: child child: child
); );
} }
......
...@@ -61,9 +61,12 @@ class _PopupMenu<T> extends StatelessComponent { ...@@ -61,9 +61,12 @@ class _PopupMenu<T> extends StatelessComponent {
for (int i = 0; i < route.items.length; ++i) { for (int i = 0; i < route.items.length; ++i) {
double start = (i + 1) * unit; double start = (i + 1) * unit;
double end = (start + 1.5 * unit).clamp(0.0, 1.0); double end = (start + 1.5 * unit).clamp(0.0, 1.0);
CurvedAnimation opacity = new CurvedAnimation(
parent: route.animation,
curve: new Interval(start, end)
);
children.add(new FadeTransition( children.add(new FadeTransition(
performance: route.performance, opacity: opacity,
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(start, end)),
child: new InkWell( child: new InkWell(
onTap: () => Navigator.pop(context, route.items[i].value), onTap: () => Navigator.pop(context, route.items[i].value),
child: route.items[i] child: route.items[i]
...@@ -71,42 +74,44 @@ class _PopupMenu<T> extends StatelessComponent { ...@@ -71,42 +74,44 @@ class _PopupMenu<T> extends StatelessComponent {
); );
} }
final AnimatedValue<double> opacity = new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(0.0, 1.0 / 3.0)); final CurveTween opacity = new CurveTween(curve: new Interval(0.0, 1.0 / 3.0));
final AnimatedValue<double> width = new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(0.0, unit)); final CurveTween width = new CurveTween(curve: new Interval(0.0, unit));
final AnimatedValue<double> height = new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(0.0, unit * route.items.length)); final CurveTween height = new CurveTween(curve: new Interval(0.0, unit * route.items.length));
Widget child = new ConstrainedBox(
constraints: new BoxConstraints(
minWidth: _kMenuMinWidth,
maxWidth: _kMenuMaxWidth
),
child: new IntrinsicWidth(
stepWidth: _kMenuWidthStep,
child: new Block(
children,
padding: const EdgeDims.symmetric(
vertical: _kMenuVerticalPadding
)
)
)
);
return new BuilderTransition( return new AnimatedBuilder(
performance: route.performance, animation: route.animation,
variables: <AnimatedValue<double>>[opacity, width, height], builder: (BuildContext context, Widget child) {
builder: (BuildContext context) {
return new Opacity( return new Opacity(
opacity: opacity.value, opacity: opacity.evaluate(route.animation),
child: new Material( child: new Material(
type: MaterialType.card, type: MaterialType.card,
elevation: route.elevation, elevation: route.elevation,
child: new Align( child: new Align(
alignment: const FractionalOffset(1.0, 0.0), alignment: const FractionalOffset(1.0, 0.0),
widthFactor: width.value, widthFactor: width.evaluate(route.animation),
heightFactor: height.value, heightFactor: height.evaluate(route.animation),
child: new ConstrainedBox( child: child
constraints: new BoxConstraints(
minWidth: _kMenuMinWidth,
maxWidth: _kMenuMaxWidth
),
child: new IntrinsicWidth(
stepWidth: _kMenuWidthStep,
child: new Block(
children,
padding: const EdgeDims.symmetric(
vertical: _kMenuVerticalPadding
)
)
)
)
) )
) )
); );
} },
child: child
); );
} }
} }
...@@ -127,18 +132,18 @@ class _PopupMenuRoute<T> extends PopupRoute<T> { ...@@ -127,18 +132,18 @@ class _PopupMenuRoute<T> extends PopupRoute<T> {
return position; return position;
} }
PerformanceView createPerformance() { Animated<double> createAnimation() {
return new CurvedPerformance( return new CurvedAnimation(
super.createPerformance(), parent: super.createAnimation(),
reverseCurve: new Interval(0.0, _kMenuCloseIntervalEnd) reverseCurve: new Interval(0.0, _kMenuCloseIntervalEnd)
); );
} }
Duration get transitionDuration => _kMenuDuration; Duration get transitionDuration => _kMenuDuration;
bool get barrierDismissable => true; bool get barrierDismissable => true;
Color get barrierColor => null; Color get barrierColor => null;
Widget buildPage(BuildContext context, PerformanceView performance, PerformanceView forwardPerformance) { Widget buildPage(BuildContext context, Animated<double> animation, Animated<double> forwardAnimation) {
return new _PopupMenu(route: this); return new _PopupMenu(route: this);
} }
} }
......
...@@ -27,7 +27,7 @@ abstract class ProgressIndicator extends StatefulComponent { ...@@ -27,7 +27,7 @@ abstract class ProgressIndicator extends StatefulComponent {
Color _getBackgroundColor(BuildContext context) => Theme.of(context).primarySwatch[200]; Color _getBackgroundColor(BuildContext context) => Theme.of(context).primarySwatch[200];
Color _getValueColor(BuildContext context) => Theme.of(context).primaryColor; Color _getValueColor(BuildContext context) => Theme.of(context).primaryColor;
Widget _buildIndicator(BuildContext context, double performanceValue); Widget _buildIndicator(BuildContext context, double animationValue);
_ProgressIndicatorState createState() => new _ProgressIndicatorState(); _ProgressIndicatorState createState() => new _ProgressIndicatorState();
...@@ -38,36 +38,33 @@ abstract class ProgressIndicator extends StatefulComponent { ...@@ -38,36 +38,33 @@ abstract class ProgressIndicator extends StatefulComponent {
} }
class _ProgressIndicatorState extends State<ProgressIndicator> { class _ProgressIndicatorState extends State<ProgressIndicator> {
Animated<double> _animation;
ValuePerformance<double> _performance; AnimationController _controller;
void initState() { void initState() {
super.initState(); super.initState();
_performance = new ValuePerformance<double>( _controller = new AnimationController(
variable: new AnimatedValue<double>(0.0, end: 1.0, curve: Curves.ease),
duration: const Duration(milliseconds: 1500) duration: const Duration(milliseconds: 1500)
); )..addStatusListener((PerformanceStatus status) {
_performance.addStatusListener((PerformanceStatus status) {
if (status == PerformanceStatus.completed) if (status == PerformanceStatus.completed)
_restartAnimation(); _restartAnimation();
}); })..forward();
_performance.play(); _animation = new CurvedAnimation(parent: _controller, curve: Curves.ease);
} }
void _restartAnimation() { void _restartAnimation() {
_performance.progress = 0.0; _controller.value = 0.0;
_performance.play(); _controller.forward();
} }
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (config.value != null) if (config.value != null)
return config._buildIndicator(context, _performance.value); return config._buildIndicator(context, _animation.value);
return new BuilderTransition( return new AnimatedBuilder(
variables: <AnimatedValue<double>>[_performance.variable], animation: _animation,
performance: _performance.view, builder: (BuildContext context, Widget child) {
builder: (BuildContext context) { return config._buildIndicator(context, _animation.value);
return config._buildIndicator(context, _performance.value);
} }
); );
} }
...@@ -78,13 +75,13 @@ class _LinearProgressIndicatorPainter extends CustomPainter { ...@@ -78,13 +75,13 @@ class _LinearProgressIndicatorPainter extends CustomPainter {
this.backgroundColor, this.backgroundColor,
this.valueColor, this.valueColor,
this.value, this.value,
this.performanceValue this.animationValue
}); });
final Color backgroundColor; final Color backgroundColor;
final Color valueColor; final Color valueColor;
final double value; final double value;
final double performanceValue; final double animationValue;
void paint(Canvas canvas, Size size) { void paint(Canvas canvas, Size size) {
Paint paint = new Paint() Paint paint = new Paint()
...@@ -97,7 +94,7 @@ class _LinearProgressIndicatorPainter extends CustomPainter { ...@@ -97,7 +94,7 @@ class _LinearProgressIndicatorPainter extends CustomPainter {
double width = value.clamp(0.0, 1.0) * size.width; double width = value.clamp(0.0, 1.0) * size.width;
canvas.drawRect(Point.origin & new Size(width, size.height), paint); canvas.drawRect(Point.origin & new Size(width, size.height), paint);
} else { } else {
double startX = size.width * (1.5 * performanceValue - 0.5); double startX = size.width * (1.5 * animationValue - 0.5);
double endX = startX + 0.5 * size.width; double endX = startX + 0.5 * size.width;
double x = startX.clamp(0.0, size.width); double x = startX.clamp(0.0, size.width);
double width = endX.clamp(0.0, size.width) - x; double width = endX.clamp(0.0, size.width) - x;
...@@ -109,7 +106,7 @@ class _LinearProgressIndicatorPainter extends CustomPainter { ...@@ -109,7 +106,7 @@ class _LinearProgressIndicatorPainter extends CustomPainter {
return oldPainter.backgroundColor != backgroundColor return oldPainter.backgroundColor != backgroundColor
|| oldPainter.valueColor != valueColor || oldPainter.valueColor != valueColor
|| oldPainter.value != value || oldPainter.value != value
|| oldPainter.performanceValue != performanceValue; || oldPainter.animationValue != animationValue;
} }
} }
...@@ -119,7 +116,7 @@ class LinearProgressIndicator extends ProgressIndicator { ...@@ -119,7 +116,7 @@ class LinearProgressIndicator extends ProgressIndicator {
double value double value
}) : super(key: key, value: value); }) : super(key: key, value: value);
Widget _buildIndicator(BuildContext context, double performanceValue) { Widget _buildIndicator(BuildContext context, double animationValue) {
return new Container( return new Container(
constraints: new BoxConstraints.tightFor( constraints: new BoxConstraints.tightFor(
width: double.INFINITY, width: double.INFINITY,
...@@ -130,7 +127,7 @@ class LinearProgressIndicator extends ProgressIndicator { ...@@ -130,7 +127,7 @@ class LinearProgressIndicator extends ProgressIndicator {
backgroundColor: _getBackgroundColor(context), backgroundColor: _getBackgroundColor(context),
valueColor: _getValueColor(context), valueColor: _getValueColor(context),
value: value, value: value,
performanceValue: performanceValue animationValue: animationValue
) )
) )
); );
...@@ -147,12 +144,12 @@ class _CircularProgressIndicatorPainter extends CustomPainter { ...@@ -147,12 +144,12 @@ class _CircularProgressIndicatorPainter extends CustomPainter {
const _CircularProgressIndicatorPainter({ const _CircularProgressIndicatorPainter({
this.valueColor, this.valueColor,
this.value, this.value,
this.performanceValue this.animationValue
}); });
final Color valueColor; final Color valueColor;
final double value; final double value;
final double performanceValue; final double animationValue;
void paint(Canvas canvas, Size size) { void paint(Canvas canvas, Size size) {
Paint paint = new Paint() Paint paint = new Paint()
...@@ -166,7 +163,7 @@ class _CircularProgressIndicatorPainter extends CustomPainter { ...@@ -166,7 +163,7 @@ class _CircularProgressIndicatorPainter extends CustomPainter {
..arcTo(Point.origin & size, _kStartAngle, angle, false); ..arcTo(Point.origin & size, _kStartAngle, angle, false);
canvas.drawPath(path, paint); canvas.drawPath(path, paint);
} else { } else {
double startAngle = _kTwoPI * (1.75 * performanceValue - 0.75); double startAngle = _kTwoPI * (1.75 * animationValue - 0.75);
double endAngle = startAngle + _kTwoPI * 0.75; double endAngle = startAngle + _kTwoPI * 0.75;
double arcAngle = startAngle.clamp(0.0, _kTwoPI); double arcAngle = startAngle.clamp(0.0, _kTwoPI);
double arcSweep = endAngle.clamp(0.0, _kTwoPI) - arcAngle; double arcSweep = endAngle.clamp(0.0, _kTwoPI) - arcAngle;
...@@ -179,7 +176,7 @@ class _CircularProgressIndicatorPainter extends CustomPainter { ...@@ -179,7 +176,7 @@ class _CircularProgressIndicatorPainter extends CustomPainter {
bool shouldRepaint(_CircularProgressIndicatorPainter oldPainter) { bool shouldRepaint(_CircularProgressIndicatorPainter oldPainter) {
return oldPainter.valueColor != valueColor return oldPainter.valueColor != valueColor
|| oldPainter.value != value || oldPainter.value != value
|| oldPainter.performanceValue != performanceValue; || oldPainter.animationValue != animationValue;
} }
} }
...@@ -189,7 +186,7 @@ class CircularProgressIndicator extends ProgressIndicator { ...@@ -189,7 +186,7 @@ class CircularProgressIndicator extends ProgressIndicator {
double value double value
}) : super(key: key, value: value); }) : super(key: key, value: value);
Widget _buildIndicator(BuildContext context, double performanceValue) { Widget _buildIndicator(BuildContext context, double animationValue) {
return new Container( return new Container(
constraints: new BoxConstraints( constraints: new BoxConstraints(
minWidth: _kMinCircularProgressIndicatorSize, minWidth: _kMinCircularProgressIndicatorSize,
...@@ -199,7 +196,7 @@ class CircularProgressIndicator extends ProgressIndicator { ...@@ -199,7 +196,7 @@ class CircularProgressIndicator extends ProgressIndicator {
painter: new _CircularProgressIndicatorPainter( painter: new _CircularProgressIndicatorPainter(
valueColor: _getValueColor(context), valueColor: _getValueColor(context),
value: value, value: value,
performanceValue: performanceValue animationValue: animationValue
) )
) )
); );
......
...@@ -111,18 +111,18 @@ class _FloatingActionButtonTransition extends StatefulComponent { ...@@ -111,18 +111,18 @@ class _FloatingActionButtonTransition extends StatefulComponent {
} }
class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTransition> { class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTransition> {
final Performance performance = new Performance(duration: _kFloatingActionButtonSegue); final AnimationController controller = new AnimationController(duration: _kFloatingActionButtonSegue);
Widget oldChild; Widget oldChild;
void initState() { void initState() {
super.initState(); super.initState();
performance.play().then((_) { controller.forward().then((_) {
oldChild = null; oldChild = null;
}); });
} }
void dispose() { void dispose() {
performance.stop(); controller.stop();
super.dispose(); super.dispose();
} }
...@@ -130,9 +130,9 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr ...@@ -130,9 +130,9 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr
if (Widget.canUpdate(oldConfig.child, config.child)) if (Widget.canUpdate(oldConfig.child, config.child))
return; return;
oldChild = oldConfig.child; oldChild = oldConfig.child;
performance controller
..progress = 0.0 ..value = 0.0
..play().then((_) { ..forward().then((_) {
oldChild = null; oldChild = null;
}); });
} }
...@@ -141,15 +141,23 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr ...@@ -141,15 +141,23 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr
final List<Widget> children = new List<Widget>(); final List<Widget> children = new List<Widget>();
if (oldChild != null) { if (oldChild != null) {
children.add(new ScaleTransition( children.add(new ScaleTransition(
scale: new AnimatedValue<double>(1.0, end: 0.0, curve: new Interval(0.0, 0.5, curve: Curves.easeIn)), // TODO(abarth): We should use ReversedAnimation here.
performance: performance, scale: new Tween<double>(
begin: 1.0,
end: 0.0
).animate(new CurvedAnimation(
parent: controller,
curve: const Interval(0.0, 0.5, curve: Curves.easeIn)
)),
child: oldChild child: oldChild
)); ));
} }
children.add(new ScaleTransition( children.add(new ScaleTransition(
scale: new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(0.5, 1.0, curve: Curves.easeIn)), scale: new CurvedAnimation(
performance: performance, parent: controller,
curve: const Interval(0.5, 1.0, curve: Curves.easeIn)
),
child: config.child child: config.child
)); ));
...@@ -190,22 +198,22 @@ class ScaffoldState extends State<Scaffold> { ...@@ -190,22 +198,22 @@ class ScaffoldState extends State<Scaffold> {
// SNACKBAR API // SNACKBAR API
Queue<ScaffoldFeatureController<SnackBar>> _snackBars = new Queue<ScaffoldFeatureController<SnackBar>>(); Queue<ScaffoldFeatureController<SnackBar>> _snackBars = new Queue<ScaffoldFeatureController<SnackBar>>();
Performance _snackBarPerformance; AnimationController _snackBarController;
Timer _snackBarTimer; Timer _snackBarTimer;
ScaffoldFeatureController showSnackBar(SnackBar snackbar) { ScaffoldFeatureController showSnackBar(SnackBar snackbar) {
_snackBarPerformance ??= SnackBar.createPerformanceController() _snackBarController ??= SnackBar.createAnimationController()
..addStatusListener(_handleSnackBarStatusChange); ..addStatusListener(_handleSnackBarStatusChange);
if (_snackBars.isEmpty) { if (_snackBars.isEmpty) {
assert(_snackBarPerformance.isDismissed); assert(_snackBarController.isDismissed);
_snackBarPerformance.forward(); _snackBarController.forward();
} }
ScaffoldFeatureController<SnackBar> controller; ScaffoldFeatureController<SnackBar> controller;
controller = new ScaffoldFeatureController<SnackBar>._( controller = new ScaffoldFeatureController<SnackBar>._(
// We provide a fallback key so that if back-to-back snackbars happen to // We provide a fallback key so that if back-to-back snackbars happen to
// match in structure, material ink splashes and highlights don't survive // match in structure, material ink splashes and highlights don't survive
// from one to the next. // from one to the next.
snackbar.withPerformance(_snackBarPerformance, fallbackKey: new UniqueKey()), snackbar.withAnimation(_snackBarController, fallbackKey: new UniqueKey()),
new Completer(), new Completer(),
() { () {
assert(_snackBars.first == controller); assert(_snackBars.first == controller);
...@@ -227,7 +235,7 @@ class ScaffoldState extends State<Scaffold> { ...@@ -227,7 +235,7 @@ class ScaffoldState extends State<Scaffold> {
_snackBars.removeFirst(); _snackBars.removeFirst();
}); });
if (_snackBars.isNotEmpty) if (_snackBars.isNotEmpty)
_snackBarPerformance.forward(); _snackBarController.forward();
break; break;
case PerformanceStatus.completed: case PerformanceStatus.completed:
setState(() { setState(() {
...@@ -242,10 +250,10 @@ class ScaffoldState extends State<Scaffold> { ...@@ -242,10 +250,10 @@ class ScaffoldState extends State<Scaffold> {
} }
void _hideSnackBar() { void _hideSnackBar() {
assert(_snackBarPerformance.status == PerformanceStatus.forward || assert(_snackBarController.status == PerformanceStatus.forward ||
_snackBarPerformance.status == PerformanceStatus.completed); _snackBarController.status == PerformanceStatus.completed);
_snackBars.first._completer.complete(); _snackBars.first._completer.complete();
_snackBarPerformance.reverse(); _snackBarController.reverse();
_snackBarTimer = null; _snackBarTimer = null;
} }
...@@ -262,7 +270,7 @@ class ScaffoldState extends State<Scaffold> { ...@@ -262,7 +270,7 @@ class ScaffoldState extends State<Scaffold> {
} }
Completer completer = new Completer(); Completer completer = new Completer();
GlobalKey<_PersistentBottomSheetState> bottomSheetKey = new GlobalKey<_PersistentBottomSheetState>(); GlobalKey<_PersistentBottomSheetState> bottomSheetKey = new GlobalKey<_PersistentBottomSheetState>();
Performance performance = BottomSheet.createPerformanceController() AnimationController controller = BottomSheet.createAnimationController()
..forward(); ..forward();
_PersistentBottomSheet bottomSheet; _PersistentBottomSheet bottomSheet;
LocalHistoryEntry entry = new LocalHistoryEntry( LocalHistoryEntry entry = new LocalHistoryEntry(
...@@ -278,7 +286,7 @@ class ScaffoldState extends State<Scaffold> { ...@@ -278,7 +286,7 @@ class ScaffoldState extends State<Scaffold> {
); );
bottomSheet = new _PersistentBottomSheet( bottomSheet = new _PersistentBottomSheet(
key: bottomSheetKey, key: bottomSheetKey,
performance: performance, animationController: controller,
onClosing: () { onClosing: () {
assert(_currentBottomSheet._widget == bottomSheet); assert(_currentBottomSheet._widget == bottomSheet);
entry.remove(); entry.remove();
...@@ -307,8 +315,8 @@ class ScaffoldState extends State<Scaffold> { ...@@ -307,8 +315,8 @@ class ScaffoldState extends State<Scaffold> {
// INTERNALS // INTERNALS
void dispose() { void dispose() {
_snackBarPerformance?.stop(); _snackBarController?.stop();
_snackBarPerformance = null; _snackBarController = null;
_snackBarTimer?.cancel(); _snackBarTimer?.cancel();
_snackBarTimer = null; _snackBarTimer = null;
super.dispose(); super.dispose();
...@@ -357,7 +365,7 @@ class ScaffoldState extends State<Scaffold> { ...@@ -357,7 +365,7 @@ class ScaffoldState extends State<Scaffold> {
if (_snackBars.length > 0) { if (_snackBars.length > 0) {
ModalRoute route = ModalRoute.of(context); ModalRoute route = ModalRoute.of(context);
if (route == null || route.isCurrent) { if (route == null || route.isCurrent) {
if (_snackBarPerformance.isCompleted && _snackBarTimer == null) if (_snackBarController.isCompleted && _snackBarTimer == null)
_snackBarTimer = new Timer(_snackBars.first._widget.duration, _hideSnackBar); _snackBarTimer = new Timer(_snackBars.first._widget.duration, _hideSnackBar);
} else { } else {
_snackBarTimer?.cancel(); _snackBarTimer?.cancel();
...@@ -420,13 +428,13 @@ class ScaffoldFeatureController<T extends Widget> { ...@@ -420,13 +428,13 @@ class ScaffoldFeatureController<T extends Widget> {
class _PersistentBottomSheet extends StatefulComponent { class _PersistentBottomSheet extends StatefulComponent {
_PersistentBottomSheet({ _PersistentBottomSheet({
Key key, Key key,
this.performance, this.animationController,
this.onClosing, this.onClosing,
this.onDismissed, this.onDismissed,
this.builder this.builder
}) : super(key: key); }) : super(key: key);
final Performance performance; final AnimationController animationController;
final VoidCallback onClosing; final VoidCallback onClosing;
final VoidCallback onDismissed; final VoidCallback onDismissed;
final WidgetBuilder builder; final WidgetBuilder builder;
...@@ -441,22 +449,22 @@ class _PersistentBottomSheetState extends State<_PersistentBottomSheet> { ...@@ -441,22 +449,22 @@ class _PersistentBottomSheetState extends State<_PersistentBottomSheet> {
void initState() { void initState() {
super.initState(); super.initState();
assert(config.performance.status == PerformanceStatus.forward); assert(config.animationController.status == PerformanceStatus.forward);
config.performance.addStatusListener(_handleStatusChange); config.animationController.addStatusListener(_handleStatusChange);
} }
void didUpdateConfig(_PersistentBottomSheet oldConfig) { void didUpdateConfig(_PersistentBottomSheet oldConfig) {
super.didUpdateConfig(oldConfig); super.didUpdateConfig(oldConfig);
assert(config.performance == oldConfig.performance); assert(config.animationController == oldConfig.animationController);
} }
void dispose() { void dispose() {
config.performance.stop(); config.animationController.stop();
super.dispose(); super.dispose();
} }
void close() { void close() {
config.performance.reverse(); config.animationController.reverse();
} }
void _handleStatusChange(PerformanceStatus status) { void _handleStatusChange(PerformanceStatus status) {
...@@ -465,12 +473,17 @@ class _PersistentBottomSheetState extends State<_PersistentBottomSheet> { ...@@ -465,12 +473,17 @@ class _PersistentBottomSheetState extends State<_PersistentBottomSheet> {
} }
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new AlignTransition( return new AnimatedBuilder(
performance: config.performance, animation: config.animationController,
alignment: new AnimatedValue<FractionalOffset>(const FractionalOffset(0.0, 0.0)), builder: (BuildContext context, Widget child) {
heightFactor: new AnimatedValue<double>(0.0, end: 1.0), return new Align(
alignment: const FractionalOffset(0.0, 0.0),
heightFactor: config.animationController.value,
child: child
);
},
child: new BottomSheet( child: new BottomSheet(
performance: config.performance, animationController: config.animationController,
onClosing: config.onClosing, onClosing: config.onClosing,
builder: config.builder builder: config.builder
) )
......
...@@ -28,6 +28,7 @@ const Color _kSnackBackground = const Color(0xFF323232); ...@@ -28,6 +28,7 @@ const Color _kSnackBackground = const Color(0xFF323232);
const Duration _kSnackBarTransitionDuration = const Duration(milliseconds: 250); const Duration _kSnackBarTransitionDuration = const Duration(milliseconds: 250);
const Duration kSnackBarShortDisplayDuration = const Duration(milliseconds: 1500); const Duration kSnackBarShortDisplayDuration = const Duration(milliseconds: 1500);
const Duration kSnackBarMediumDisplayDuration = const Duration(milliseconds: 2750); const Duration kSnackBarMediumDisplayDuration = const Duration(milliseconds: 2750);
const Curve _snackBarHeightCurve = Curves.fastOutSlowIn;
const Curve _snackBarFadeCurve = const Interval(0.72, 1.0, curve: Curves.fastOutSlowIn); const Curve _snackBarFadeCurve = const Interval(0.72, 1.0, curve: Curves.fastOutSlowIn);
class SnackBarAction extends StatelessComponent { class SnackBarAction extends StatelessComponent {
...@@ -56,7 +57,7 @@ class SnackBar extends StatelessComponent { ...@@ -56,7 +57,7 @@ class SnackBar extends StatelessComponent {
this.content, this.content,
this.actions, this.actions,
this.duration: kSnackBarShortDisplayDuration, this.duration: kSnackBarShortDisplayDuration,
this.performance this.animation
}) : super(key: key) { }) : super(key: key) {
assert(content != null); assert(content != null);
} }
...@@ -64,10 +65,10 @@ class SnackBar extends StatelessComponent { ...@@ -64,10 +65,10 @@ class SnackBar extends StatelessComponent {
final Widget content; final Widget content;
final List<SnackBarAction> actions; final List<SnackBarAction> actions;
final Duration duration; final Duration duration;
final PerformanceView performance; final Animated<double> animation;
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(performance != null); assert(animation != null);
List<Widget> children = <Widget>[ List<Widget> children = <Widget>[
new Flexible( new Flexible(
child: new Container( child: new Container(
...@@ -81,12 +82,19 @@ class SnackBar extends StatelessComponent { ...@@ -81,12 +82,19 @@ class SnackBar extends StatelessComponent {
]; ];
if (actions != null) if (actions != null)
children.addAll(actions); children.addAll(actions);
CurvedAnimation heightAnimation = new CurvedAnimation(parent: animation, curve: _snackBarHeightCurve);
CurvedAnimation fadeAnimation = new CurvedAnimation(parent: animation, curve: _snackBarFadeCurve);
ThemeData theme = Theme.of(context); ThemeData theme = Theme.of(context);
return new ClipRect( return new ClipRect(
child: new AlignTransition( child: new AnimatedBuilder(
performance: performance, animation: heightAnimation,
alignment: new AnimatedValue<FractionalOffset>(const FractionalOffset(0.0, 0.0)), builder: (BuildContext context, Widget child) {
heightFactor: new AnimatedValue<double>(0.0, end: 1.0, curve: Curves.fastOutSlowIn), return new Align(
alignment: const FractionalOffset(0.0, 0.0),
heightFactor: heightAnimation.value,
child: child
);
},
child: new Material( child: new Material(
elevation: 6, elevation: 6,
color: _kSnackBackground, color: _kSnackBackground,
...@@ -100,8 +108,7 @@ class SnackBar extends StatelessComponent { ...@@ -100,8 +108,7 @@ class SnackBar extends StatelessComponent {
text: Typography.white text: Typography.white
), ),
child: new FadeTransition( child: new FadeTransition(
performance: performance, opacity: fadeAnimation,
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: _snackBarFadeCurve),
child: new Row( child: new Row(
children: children, children: children,
alignItems: FlexAlignItems.center alignItems: FlexAlignItems.center
...@@ -116,20 +123,20 @@ class SnackBar extends StatelessComponent { ...@@ -116,20 +123,20 @@ class SnackBar extends StatelessComponent {
// API for Scaffold.addSnackBar(): // API for Scaffold.addSnackBar():
static Performance createPerformanceController() { static AnimationController createAnimationController() {
return new Performance( return new AnimationController(
duration: _kSnackBarTransitionDuration, duration: _kSnackBarTransitionDuration,
debugLabel: 'SnackBar' debugLabel: 'SnackBar'
); );
} }
SnackBar withPerformance(Performance newPerformance, { Key fallbackKey }) { SnackBar withAnimation(Animated<double> newAnimation, { Key fallbackKey }) {
return new SnackBar( return new SnackBar(
key: key ?? fallbackKey, key: key ?? fallbackKey,
content: content, content: content,
actions: actions, actions: actions,
duration: duration, duration: duration,
performance: newPerformance animation: newAnimation
); );
} }
} }
...@@ -415,10 +415,10 @@ class TabBarSelection<T> extends StatefulComponent { ...@@ -415,10 +415,10 @@ class TabBarSelection<T> extends StatefulComponent {
class TabBarSelectionState<T> extends State<TabBarSelection<T>> { class TabBarSelectionState<T> extends State<TabBarSelection<T>> {
Animation get animation => _controller.view; Animated<double> get animation => _controller.view;
// Both the TabBar and TabBarView classes access _performance because they // Both the TabBar and TabBarView classes access _performance because they
// alternately drive selection progress between tabs. // alternately drive selection progress between tabs.
final AnimationController _controller = new AnimationController(duration: _kTabBarScroll, progress: 1.0); final AnimationController _controller = new AnimationController(duration: _kTabBarScroll, value: 1.0);
final Map<T, int> _valueToIndex = new Map<T, int>(); final Map<T, int> _valueToIndex = new Map<T, int>();
void _initValueToIndex() { void _initValueToIndex() {
...@@ -480,22 +480,22 @@ class TabBarSelectionState<T> extends State<TabBarSelection<T>> { ...@@ -480,22 +480,22 @@ class TabBarSelectionState<T> extends State<TabBarSelection<T>> {
// one. Convert progress to reflect the fact that we're now moving between (just) // one. Convert progress to reflect the fact that we're now moving between (just)
// the previous and current selection index. // the previous and current selection index.
double progress; double value;
if (_controller.status == PerformanceStatus.completed) if (_controller.status == PerformanceStatus.completed)
progress = 0.0; value = 0.0;
else if (_previousValue == values.first) else if (_previousValue == values.first)
progress = _controller.progress; value = _controller.value;
else if (_previousValue == values.last) else if (_previousValue == values.last)
progress = 1.0 - _controller.progress; value = 1.0 - _controller.value;
else if (previousIndex < index) else if (previousIndex < index)
progress = (_controller.progress - 0.5) * 2.0; value = (_controller.value - 0.5) * 2.0;
else else
progress = 1.0 - _controller.progress * 2.0; value = 1.0 - _controller.value * 2.0;
_controller _controller
..progress = progress ..value = value
..forward().then((_) { ..forward().then((_) {
if (_controller.progress == 1.0) { if (_controller.value == 1.0) {
if (config.onChanged != null) if (config.onChanged != null)
config.onChanged(_value); config.onChanged(_value);
_valueIsChanging = false; _valueIsChanging = false;
...@@ -612,7 +612,7 @@ class _TabBarState<T> extends ScrollableState<TabBar<T>> implements TabBarSelect ...@@ -612,7 +612,7 @@ class _TabBarState<T> extends ScrollableState<TabBar<T>> implements TabBarSelect
_valueIsChanging = true; _valueIsChanging = true;
} }
Rect oldRect = _indicatorRect; Rect oldRect = _indicatorRect;
double t = _selection.animation.progress; double t = _selection.animation.value;
if (_valueIsChanging) { if (_valueIsChanging) {
// When _valueIsChanging is true, we're animating based on a ticker and // When _valueIsChanging is true, we're animating based on a ticker and
// want to curve the animation. When _valueIsChanging is false, we're // want to curve the animation. When _valueIsChanging is false, we're
...@@ -676,9 +676,9 @@ class _TabBarState<T> extends ScrollableState<TabBar<T>> implements TabBarSelect ...@@ -676,9 +676,9 @@ class _TabBarState<T> extends ScrollableState<TabBar<T>> implements TabBarSelect
labelColor = isSelectedTab ? selectedColor : color; labelColor = isSelectedTab ? selectedColor : color;
if (_selection.valueIsChanging) { if (_selection.valueIsChanging) {
if (isSelectedTab) if (isSelectedTab)
labelColor = Color.lerp(color, selectedColor, _selection.animation.progress); labelColor = Color.lerp(color, selectedColor, _selection.animation.value);
else if (isPreviouslySelectedTab) else if (isPreviouslySelectedTab)
labelColor = Color.lerp(selectedColor, color, _selection.animation.progress); labelColor = Color.lerp(selectedColor, color, _selection.animation.value);
} }
} }
return new _Tab( return new _Tab(
...@@ -876,7 +876,7 @@ class _TabBarViewState extends PageableListState<TabBarView> implements TabBarSe ...@@ -876,7 +876,7 @@ class _TabBarViewState extends PageableListState<TabBarView> implements TabBarSe
return; return;
// The TabBar is driving the TabBarSelection performance. // The TabBar is driving the TabBarSelection performance.
final Animation animation = _selection.animation; final Animated<double> animation = _selection.animation;
if (animation.status == PerformanceStatus.completed) { if (animation.status == PerformanceStatus.completed) {
_updateItemsAndScrollBehavior(); _updateItemsAndScrollBehavior();
...@@ -898,9 +898,9 @@ class _TabBarViewState extends PageableListState<TabBarView> implements TabBarSe ...@@ -898,9 +898,9 @@ class _TabBarViewState extends PageableListState<TabBarView> implements TabBarSe
} }
if (_scrollDirection == AnimationDirection.forward) if (_scrollDirection == AnimationDirection.forward)
scrollTo(animation.progress); scrollTo(animation.value);
else else
scrollTo(1.0 - animation.progress); scrollTo(1.0 - animation.value);
} }
void dispatchOnScroll() { void dispatchOnScroll() {
...@@ -911,9 +911,9 @@ class _TabBarViewState extends PageableListState<TabBarView> implements TabBarSe ...@@ -911,9 +911,9 @@ class _TabBarViewState extends PageableListState<TabBarView> implements TabBarSe
final AnimationController controller = _selection._controller; final AnimationController controller = _selection._controller;
if (_selection.index == 0 || _selection.index == _tabCount - 1) if (_selection.index == 0 || _selection.index == _tabCount - 1)
controller.progress = scrollOffset; controller.value = scrollOffset;
else else
controller.progress = scrollOffset / 2.0; controller.value = scrollOffset / 2.0;
} }
Future fling(Offset scrollVelocity) { Future fling(Offset scrollVelocity) {
......
...@@ -71,13 +71,13 @@ class Tooltip extends StatefulComponent { ...@@ -71,13 +71,13 @@ class Tooltip extends StatefulComponent {
class _TooltipState extends State<Tooltip> { class _TooltipState extends State<Tooltip> {
Performance _performance; AnimationController _controller;
OverlayEntry _entry; OverlayEntry _entry;
Timer _timer; Timer _timer;
void initState() { void initState() {
super.initState(); super.initState();
_performance = new Performance(duration: config.fadeDuration) _controller = new AnimationController(duration: config.fadeDuration)
..addStatusListener((PerformanceStatus status) { ..addStatusListener((PerformanceStatus status) {
switch (status) { switch (status) {
case PerformanceStatus.completed: case PerformanceStatus.completed:
...@@ -100,7 +100,7 @@ class _TooltipState extends State<Tooltip> { ...@@ -100,7 +100,7 @@ class _TooltipState extends State<Tooltip> {
void didUpdateConfig(Tooltip oldConfig) { void didUpdateConfig(Tooltip oldConfig) {
super.didUpdateConfig(oldConfig); super.didUpdateConfig(oldConfig);
if (config.fadeDuration != oldConfig.fadeDuration) if (config.fadeDuration != oldConfig.fadeDuration)
_performance.duration = config.fadeDuration; _controller.duration = config.fadeDuration;
if (_entry != null && if (_entry != null &&
(config.message != oldConfig.message || (config.message != oldConfig.message ||
config.backgroundColor != oldConfig.backgroundColor || config.backgroundColor != oldConfig.backgroundColor ||
...@@ -117,7 +117,7 @@ class _TooltipState extends State<Tooltip> { ...@@ -117,7 +117,7 @@ class _TooltipState extends State<Tooltip> {
} }
void resetShowTimer() { void resetShowTimer() {
assert(_performance.status == PerformanceStatus.completed); assert(_controller.status == PerformanceStatus.completed);
assert(_entry != null); assert(_entry != null);
_timer = new Timer(config.showDuration, hideTooltip); _timer = new Timer(config.showDuration, hideTooltip);
} }
...@@ -136,7 +136,10 @@ class _TooltipState extends State<Tooltip> { ...@@ -136,7 +136,10 @@ class _TooltipState extends State<Tooltip> {
height: config.height, height: config.height,
padding: config.padding, padding: config.padding,
opacity: config.opacity, opacity: config.opacity,
performance: _performance, animation: new CurvedAnimation(
parent: _controller,
curve: Curves.ease
),
target: target, target: target,
verticalOffset: config.verticalOffset, verticalOffset: config.verticalOffset,
screenEdgeMargin: config.screenEdgeMargin, screenEdgeMargin: config.screenEdgeMargin,
...@@ -146,9 +149,9 @@ class _TooltipState extends State<Tooltip> { ...@@ -146,9 +149,9 @@ class _TooltipState extends State<Tooltip> {
Overlay.of(context).insert(_entry); Overlay.of(context).insert(_entry);
} }
_timer?.cancel(); _timer?.cancel();
if (_performance.status != PerformanceStatus.completed) { if (_controller.status != PerformanceStatus.completed) {
_timer = null; _timer = null;
_performance.forward(); _controller.forward();
} else { } else {
resetShowTimer(); resetShowTimer();
} }
...@@ -158,7 +161,7 @@ class _TooltipState extends State<Tooltip> { ...@@ -158,7 +161,7 @@ class _TooltipState extends State<Tooltip> {
assert(_entry != null); assert(_entry != null);
_timer?.cancel(); _timer?.cancel();
_timer = null; _timer = null;
_performance.reverse(); _controller.reverse();
} }
void deactivate() { void deactivate() {
...@@ -232,7 +235,7 @@ class _TooltipOverlay extends StatelessComponent { ...@@ -232,7 +235,7 @@ class _TooltipOverlay extends StatelessComponent {
this.height, this.height,
this.padding, this.padding,
this.opacity, this.opacity,
this.performance, this.animation,
this.target, this.target,
this.verticalOffset, this.verticalOffset,
this.screenEdgeMargin, this.screenEdgeMargin,
...@@ -246,7 +249,7 @@ class _TooltipOverlay extends StatelessComponent { ...@@ -246,7 +249,7 @@ class _TooltipOverlay extends StatelessComponent {
final double borderRadius; final double borderRadius;
final double height; final double height;
final EdgeDims padding; final EdgeDims padding;
final PerformanceView performance; final Animated<double> animation;
final Point target; final Point target;
final double verticalOffset; final double verticalOffset;
final EdgeDims screenEdgeMargin; final EdgeDims screenEdgeMargin;
...@@ -267,8 +270,7 @@ class _TooltipOverlay extends StatelessComponent { ...@@ -267,8 +270,7 @@ class _TooltipOverlay extends StatelessComponent {
preferBelow: preferBelow preferBelow: preferBelow
), ),
child: new FadeTransition( child: new FadeTransition(
performance: performance, opacity: animation,
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: Curves.ease),
child: new Opacity( child: new Opacity(
opacity: opacity, opacity: opacity,
child: new Container( child: new Container(
......
...@@ -91,9 +91,9 @@ class _Entry { ...@@ -91,9 +91,9 @@ class _Entry {
} }
} }
typedef Widget TransitionBuilderCallback(Animation animation, Widget child); typedef Widget TransitionBuilderCallback(Animated<double> animation, Widget child);
Widget _identityTransition(Animation animation, Widget child) => child; Widget _identityTransition(Animated<double> animation, Widget child) => child;
class EnterExitTransition extends StatefulComponent { class EnterExitTransition extends StatefulComponent {
EnterExitTransition({ EnterExitTransition({
......
...@@ -73,7 +73,7 @@ class _HeroManifest { ...@@ -73,7 +73,7 @@ class _HeroManifest {
abstract class HeroHandle { abstract class HeroHandle {
bool get alwaysAnimate; bool get alwaysAnimate;
_HeroManifest _takeChild(Rect animationArea); _HeroManifest _takeChild(Rect animationArea, Animated<double> currentAnimation);
} }
class Hero extends StatefulComponent { class Hero extends StatefulComponent {
...@@ -167,7 +167,7 @@ class HeroState extends State<Hero> implements HeroHandle { ...@@ -167,7 +167,7 @@ class HeroState extends State<Hero> implements HeroHandle {
bool get alwaysAnimate => config.alwaysAnimate; bool get alwaysAnimate => config.alwaysAnimate;
_HeroManifest _takeChild(Rect animationArea) { _HeroManifest _takeChild(Rect animationArea, Animated<double> currentAnimation) {
assert(_mode == _HeroMode.measured || _mode == _HeroMode.taken); assert(_mode == _HeroMode.measured || _mode == _HeroMode.taken);
final RenderBox renderObject = context.findRenderObject(); final RenderBox renderObject = context.findRenderObject();
final Point heroTopLeft = renderObject.localToGlobal(Point.origin); final Point heroTopLeft = renderObject.localToGlobal(Point.origin);
...@@ -256,14 +256,14 @@ class _HeroQuestState implements HeroHandle { ...@@ -256,14 +256,14 @@ class _HeroQuestState implements HeroHandle {
final RelativeRect targetRect; final RelativeRect targetRect;
final int targetTurns; final int targetTurns;
final HeroState targetState; final HeroState targetState;
final AnimatedRelativeRectValue currentRect; final RelativeRectTween currentRect;
final AnimatedValue<double> currentTurns; final Tween<double> currentTurns;
bool get alwaysAnimate => true; bool get alwaysAnimate => true;
bool get taken => _taken; bool get taken => _taken;
bool _taken = false; bool _taken = false;
_HeroManifest _takeChild(Rect animationArea) { _HeroManifest _takeChild(Rect animationArea, Animated<double> currentAnimation) {
assert(!taken); assert(!taken);
_taken = true; _taken = true;
Set<HeroState> states = sourceStates; Set<HeroState> states = sourceStates;
...@@ -273,18 +273,16 @@ class _HeroQuestState implements HeroHandle { ...@@ -273,18 +273,16 @@ class _HeroQuestState implements HeroHandle {
key: key, key: key,
config: child, config: child,
sourceStates: states, sourceStates: states,
currentRect: currentRect.value, currentRect: currentRect.evaluate(currentAnimation),
currentTurns: currentTurns.value currentTurns: currentTurns.evaluate(currentAnimation)
); );
} }
Widget build(BuildContext context, PerformanceView performance) { Widget build(BuildContext context, Animated<double> animation) {
return new PositionedTransition( return new PositionedTransition(
rect: currentRect, rect: currentRect.animate(animation),
performance: performance,
child: new RotationTransition( child: new RotationTransition(
turns: currentTurns, turns: currentTurns.animate(animation),
performance: performance,
child: new KeyedSubtree( child: new KeyedSubtree(
key: key, key: key,
child: child child: child
...@@ -317,16 +315,16 @@ class HeroParty { ...@@ -317,16 +315,16 @@ class HeroParty {
return result; return result;
} }
AnimatedRelativeRectValue createAnimatedRelativeRect(RelativeRect begin, RelativeRect end, Curve curve) { RelativeRectTween createRectTween(RelativeRect begin, RelativeRect end) {
return new AnimatedRelativeRectValue(begin, end: end, curve: curve); return new RelativeRectTween(begin: begin, end: end);
} }
AnimatedValue<double> createAnimatedTurns(double begin, double end, Curve curve) { Tween<double> createTurnsTween(double begin, double end) {
assert(end.floor() == end); assert(end.floor() == end);
return new AnimatedValue<double>(begin, end: end, curve: curve); return new Tween<double>(begin: begin, end: end);
} }
void animate(Map<Object, HeroHandle> heroesFrom, Map<Object, HeroHandle> heroesTo, Rect animationArea, Curve curve) { void animate(Map<Object, HeroHandle> heroesFrom, Map<Object, HeroHandle> heroesTo, Rect animationArea) {
assert(!heroesFrom.containsKey(null)); assert(!heroesFrom.containsKey(null));
assert(!heroesTo.containsKey(null)); assert(!heroesTo.containsKey(null));
...@@ -346,9 +344,9 @@ class HeroParty { ...@@ -346,9 +344,9 @@ class HeroParty {
if ((heroPair.from == null && !heroPair.to.alwaysAnimate) || if ((heroPair.from == null && !heroPair.to.alwaysAnimate) ||
(heroPair.to == null && !heroPair.from.alwaysAnimate)) (heroPair.to == null && !heroPair.from.alwaysAnimate))
continue; continue;
_HeroManifest from = heroPair.from?._takeChild(animationArea); _HeroManifest from = heroPair.from?._takeChild(animationArea, _currentAnimation);
assert(heroPair.to == null || heroPair.to is HeroState); assert(heroPair.to == null || heroPair.to is HeroState);
_HeroManifest to = heroPair.to?._takeChild(animationArea); _HeroManifest to = heroPair.to?._takeChild(animationArea, _currentAnimation);
assert(from != null || to != null); assert(from != null || to != null);
assert(to == null || to.sourceStates.length == 1); assert(to == null || to.sourceStates.length == 1);
assert(to == null || to.currentTurns.floor() == to.currentTurns); assert(to == null || to.currentTurns.floor() == to.currentTurns);
...@@ -369,8 +367,8 @@ class HeroParty { ...@@ -369,8 +367,8 @@ class HeroParty {
targetRect: targetRect, targetRect: targetRect,
targetTurns: targetTurns.floor(), targetTurns: targetTurns.floor(),
targetState: targetState, targetState: targetState,
currentRect: createAnimatedRelativeRect(sourceRect, targetRect, curve), currentRect: createRectTween(sourceRect, targetRect),
currentTurns: createAnimatedTurns(sourceTurns, targetTurns, curve) currentTurns: createTurnsTween(sourceTurns, targetTurns)
)); ));
} }
...@@ -378,19 +376,19 @@ class HeroParty { ...@@ -378,19 +376,19 @@ class HeroParty {
_heroes = _newHeroes; _heroes = _newHeroes;
} }
PerformanceView _currentPerformance; Animated<double> _currentAnimation;
void _clearCurrentPerformance() { void _clearCurrentPerformance() {
_currentPerformance?.removeStatusListener(_handleUpdate); _currentAnimation?.removeStatusListener(_handleUpdate);
_currentPerformance = null; _currentAnimation = null;
} }
void setPerformance(PerformanceView performance) { void setAnimation(Animated<double> animation) {
assert(performance != null || _heroes.length == 0); assert(animation != null || _heroes.length == 0);
if (performance != _currentPerformance) { if (animation != _currentAnimation) {
_clearCurrentPerformance(); _clearCurrentPerformance();
_currentPerformance = performance; _currentAnimation = animation;
_currentPerformance?.addStatusListener(_handleUpdate); _currentAnimation?.addStatusListener(_handleUpdate);
} }
} }
...@@ -419,7 +417,7 @@ class HeroController extends NavigatorObserver { ...@@ -419,7 +417,7 @@ class HeroController extends NavigatorObserver {
} }
HeroParty _party; HeroParty _party;
PerformanceView _performance; Animated<double> _animation;
PageRoute _from; PageRoute _from;
PageRoute _to; PageRoute _to;
...@@ -429,11 +427,11 @@ class HeroController extends NavigatorObserver { ...@@ -429,11 +427,11 @@ class HeroController extends NavigatorObserver {
assert(navigator != null); assert(navigator != null);
assert(route != null); assert(route != null);
if (route is PageRoute) { if (route is PageRoute) {
assert(route.performance != null); assert(route.animation != null);
if (previousRoute is PageRoute) // could be null if (previousRoute is PageRoute) // could be null
_from = previousRoute; _from = previousRoute;
_to = route; _to = route;
_performance = route.performance; _animation = route.animation;
_checkForHeroQuest(); _checkForHeroQuest();
} }
} }
...@@ -442,11 +440,11 @@ class HeroController extends NavigatorObserver { ...@@ -442,11 +440,11 @@ class HeroController extends NavigatorObserver {
assert(navigator != null); assert(navigator != null);
assert(route != null); assert(route != null);
if (route is PageRoute) { if (route is PageRoute) {
assert(route.performance != null); assert(route.animation != null);
if (previousRoute is PageRoute) { if (previousRoute is PageRoute) {
_to = previousRoute; _to = previousRoute;
_from = route; _from = route;
_performance = route.performance; _animation = route.animation;
_checkForHeroQuest(); _checkForHeroQuest();
} }
} }
...@@ -454,7 +452,7 @@ class HeroController extends NavigatorObserver { ...@@ -454,7 +452,7 @@ class HeroController extends NavigatorObserver {
void _checkForHeroQuest() { void _checkForHeroQuest() {
if (_from != null && _to != null && _from != _to) { if (_from != null && _to != null && _from != _to) {
_to.offstage = _to.performance.status != PerformanceStatus.completed; _to.offstage = _to.animation.status != PerformanceStatus.completed;
Scheduler.instance.addPostFrameCallback(_updateQuest); Scheduler.instance.addPostFrameCallback(_updateQuest);
} }
} }
...@@ -463,7 +461,7 @@ class HeroController extends NavigatorObserver { ...@@ -463,7 +461,7 @@ class HeroController extends NavigatorObserver {
_removeHeroesFromOverlay(); _removeHeroesFromOverlay();
_from = null; _from = null;
_to = null; _to = null;
_performance = null; _animation = null;
} }
Rect _getAnimationArea(BuildContext context) { Rect _getAnimationArea(BuildContext context) {
...@@ -481,7 +479,7 @@ class HeroController extends NavigatorObserver { ...@@ -481,7 +479,7 @@ class HeroController extends NavigatorObserver {
void _addHeroToOverlay(Widget hero, Object tag, OverlayState overlay) { void _addHeroToOverlay(Widget hero, Object tag, OverlayState overlay) {
OverlayEntry entry = new OverlayEntry(builder: (_) => hero); OverlayEntry entry = new OverlayEntry(builder: (_) => hero);
if (_performance.direction == AnimationDirection.forward) if (_animation.direction == AnimationDirection.forward)
_to.insertHeroOverlayEntry(entry, tag, overlay); _to.insertHeroOverlayEntry(entry, tag, overlay);
else else
_from.insertHeroOverlayEntry(entry, tag, overlay); _from.insertHeroOverlayEntry(entry, tag, overlay);
...@@ -507,18 +505,21 @@ class HeroController extends NavigatorObserver { ...@@ -507,18 +505,21 @@ class HeroController extends NavigatorObserver {
Map<Object, HeroHandle> heroesTo = Hero.of(_to.subtreeContext, mostValuableKeys); Map<Object, HeroHandle> heroesTo = Hero.of(_to.subtreeContext, mostValuableKeys);
_to.offstage = false; _to.offstage = false;
PerformanceView performance = _performance; Animated<double> animation = _animation;
Curve curve = Curves.ease; Curve curve = Curves.ease;
if (performance.status == PerformanceStatus.reverse) { if (animation.status == PerformanceStatus.reverse) {
performance = new ReversePerformance(performance); animation = new ReverseAnimation(animation);
curve = new Interval(performance.progress, 1.0, curve: curve); curve = new Interval(animation.value, 1.0, curve: curve);
} }
_party.animate(heroesFrom, heroesTo, _getAnimationArea(navigator.context), curve); _party.animate(heroesFrom, heroesTo, _getAnimationArea(navigator.context));
_removeHeroesFromOverlay(); _removeHeroesFromOverlay();
_party.setPerformance(performance); _party.setAnimation(new CurvedAnimation(
parent: animation,
curve: curve
));
for (_HeroQuestState hero in _party._heroes) { for (_HeroQuestState hero in _party._heroes) {
Widget widget = hero.build(navigator.context, performance); Widget widget = hero.build(navigator.context, animation);
_addHeroToOverlay(widget, hero.tag, navigator.overlay); _addHeroToOverlay(widget, hero.tag, navigator.overlay);
} }
} }
......
...@@ -43,38 +43,23 @@ class ModalBarrier extends StatelessComponent { ...@@ -43,38 +43,23 @@ class ModalBarrier extends StatelessComponent {
} }
/// Prevents the user from interacting with widgets behind itself. /// Prevents the user from interacting with widgets behind itself.
class AnimatedModalBarrier extends StatelessComponent { class AnimatedModalBarrier extends AnimatedComponent {
AnimatedModalBarrier({ AnimatedModalBarrier({
Key key, Key key,
this.color, Animated<Color> color,
this.performance,
this.dismissable: true this.dismissable: true
}) : super(key: key); }) : color = color, super(key: key, animation: color);
/// If non-null, fill the barrier with this color. /// If non-null, fill the barrier with this color.
/// final Animated<Color> color;
/// The barrier will animate this color according to the given [performance].
final AnimatedColorValue color;
/// The performance to use when animating the given [color].
final PerformanceView performance;
/// Whether touching the barrier will pop the current route off the [Navigator]. /// Whether touching the barrier will pop the current route off the [Navigator].
final bool dismissable; final bool dismissable;
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new BuilderTransition( return new ModalBarrier(
performance: performance, color: color.value,
variables: <AnimatedColorValue>[color], dismissable: dismissable
builder: (BuildContext context) {
return new IgnorePointer(
ignoring: performance.status == PerformanceStatus.reverse,
child: new ModalBarrier(
color: color.value,
dismissable: dismissable
)
);
}
); );
} }
} }
...@@ -21,11 +21,11 @@ abstract class PageRoute<T> extends ModalRoute<T> { ...@@ -21,11 +21,11 @@ abstract class PageRoute<T> extends ModalRoute<T> {
bool canTransitionTo(TransitionRoute nextRoute) => nextRoute is PageRoute; bool canTransitionTo(TransitionRoute nextRoute) => nextRoute is PageRoute;
bool canTransitionFrom(TransitionRoute nextRoute) => nextRoute is PageRoute; bool canTransitionFrom(TransitionRoute nextRoute) => nextRoute is PageRoute;
Performance createPerformanceController() { AnimationController createAnimationController() {
Performance performance = super.createPerformanceController(); AnimationController controller = super.createAnimationController();
if (settings.isInitialRoute) if (settings.isInitialRoute)
performance.progress = 1.0; controller.value = 1.0;
return performance; return controller;
} }
/// Subclasses can override this method to customize how heroes are inserted. /// Subclasses can override this method to customize how heroes are inserted.
......
...@@ -92,25 +92,25 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> { ...@@ -92,25 +92,25 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
Duration get transitionDuration; Duration get transitionDuration;
bool get opaque; bool get opaque;
PerformanceView get performance => _performance; Animated<double> get animation => _animation;
Performance _performanceController; Animated<double> _animation;
PerformanceView _performance; AnimationController _controller;
/// Called to create the Performance object that will drive the transitions to /// Called to create the Performance object that will drive the transitions to
/// this route from the previous one, and back to the previous route from this /// this route from the previous one, and back to the previous route from this
/// one. /// one.
Performance createPerformanceController() { AnimationController createAnimationController() {
Duration duration = transitionDuration; Duration duration = transitionDuration;
assert(duration != null && duration >= Duration.ZERO); assert(duration != null && duration >= Duration.ZERO);
return new Performance(duration: duration, debugLabel: debugLabel); return new AnimationController(duration: duration, debugLabel: debugLabel);
} }
/// Called to create the PerformanceView that exposes the current progress of /// Called to create the PerformanceView that exposes the current progress of
/// the transition controlled by the Performance object created by /// the transition controlled by the Performance object created by
/// [createPerformanceController()]. /// [createAnimationController()].
PerformanceView createPerformance() { Animated<double> createAnimation() {
assert(_performanceController != null); assert(_controller != null);
return _performanceController.view; return _controller.view;
} }
T _result; T _result;
...@@ -134,33 +134,33 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> { ...@@ -134,33 +134,33 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
} }
} }
PerformanceView get forwardPerformance => _forwardPerformance; Animated<double> get forwardAnimation => _forwardAnimation;
final ProxyPerformance _forwardPerformance = new ProxyPerformance(alwaysDismissedPerformance); final ProxyAnimation _forwardAnimation = new ProxyAnimation(kAlwaysDismissedAnimation);
void install(OverlayEntry insertionPoint) { void install(OverlayEntry insertionPoint) {
_performanceController = createPerformanceController(); _controller = createAnimationController();
assert(_performanceController != null); assert(_controller != null);
_performance = createPerformance(); _animation = createAnimation();
assert(_performance != null); assert(_animation != null);
super.install(insertionPoint); super.install(insertionPoint);
} }
void didPush() { void didPush() {
_performance.addStatusListener(handleStatusChanged); _animation.addStatusListener(handleStatusChanged);
_performanceController.forward(); _controller.forward();
super.didPush(); super.didPush();
} }
void didReplace(Route oldRoute) { void didReplace(Route oldRoute) {
if (oldRoute is TransitionRoute) if (oldRoute is TransitionRoute)
_performanceController.progress = oldRoute._performanceController.progress; _controller.value = oldRoute._controller.value;
_performance.addStatusListener(handleStatusChanged); _animation.addStatusListener(handleStatusChanged);
super.didReplace(oldRoute); super.didReplace(oldRoute);
} }
bool didPop(T result) { bool didPop(T result) {
_result = result; _result = result;
_performanceController.reverse(); _controller.reverse();
_popCompleter?.complete(_result); _popCompleter?.complete(_result);
return true; return true;
} }
...@@ -177,30 +177,30 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> { ...@@ -177,30 +177,30 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
void _updateForwardPerformance(Route nextRoute) { void _updateForwardPerformance(Route nextRoute) {
if (nextRoute is TransitionRoute && canTransitionTo(nextRoute) && nextRoute.canTransitionFrom(this)) { if (nextRoute is TransitionRoute && canTransitionTo(nextRoute) && nextRoute.canTransitionFrom(this)) {
PerformanceView current = _forwardPerformance.masterPerformance; Animated<double> current = _forwardAnimation.masterAnimation;
if (current != null) { if (current != null) {
if (current is TrainHoppingPerformance) { if (current is TrainHoppingAnimation) {
TrainHoppingPerformance newPerformance; TrainHoppingAnimation newPerformance;
newPerformance = new TrainHoppingPerformance( newPerformance = new TrainHoppingAnimation(
current.currentTrain, current.currentTrain,
nextRoute.performance, nextRoute.animation,
onSwitchedTrain: () { onSwitchedTrain: () {
assert(_forwardPerformance.masterPerformance == newPerformance); assert(_forwardAnimation.masterAnimation == newPerformance);
assert(newPerformance.currentTrain == nextRoute.performance); assert(newPerformance.currentTrain == nextRoute.animation);
_forwardPerformance.masterPerformance = newPerformance.currentTrain; _forwardAnimation.masterAnimation = newPerformance.currentTrain;
newPerformance.dispose(); newPerformance.dispose();
} }
); );
_forwardPerformance.masterPerformance = newPerformance; _forwardAnimation.masterAnimation = newPerformance;
current.dispose(); current.dispose();
} else { } else {
_forwardPerformance.masterPerformance = new TrainHoppingPerformance(current, nextRoute.performance); _forwardAnimation.masterAnimation = new TrainHoppingAnimation(current, nextRoute.animation);
} }
} else { } else {
_forwardPerformance.masterPerformance = nextRoute.performance; _forwardAnimation.masterAnimation = nextRoute.animation;
} }
} else { } else {
_forwardPerformance.masterPerformance = alwaysDismissedPerformance; _forwardAnimation.masterAnimation = kAlwaysDismissedAnimation;
} }
} }
...@@ -213,12 +213,12 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> { ...@@ -213,12 +213,12 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
} }
void dispose() { void dispose() {
_performanceController.stop(); _controller.stop();
super.dispose(); super.dispose();
} }
String get debugLabel => '$runtimeType'; String get debugLabel => '$runtimeType';
String toString() => '$runtimeType(performance: $_performanceController)'; String toString() => '$runtimeType(animation: $_controller)';
} }
class LocalHistoryEntry { class LocalHistoryEntry {
...@@ -306,8 +306,8 @@ class _ModalScope extends StatefulComponent { ...@@ -306,8 +306,8 @@ class _ModalScope extends StatefulComponent {
class _ModalScopeState extends State<_ModalScope> { class _ModalScopeState extends State<_ModalScope> {
void initState() { void initState() {
super.initState(); super.initState();
config.route.performance?.addStatusListener(_performanceStatusChanged); config.route.animation?.addStatusListener(_animationStatusChanged);
config.route.forwardPerformance?.addStatusListener(_performanceStatusChanged); config.route.forwardAnimation?.addStatusListener(_animationStatusChanged);
} }
void didUpdateConfig(_ModalScope oldConfig) { void didUpdateConfig(_ModalScope oldConfig) {
...@@ -315,12 +315,12 @@ class _ModalScopeState extends State<_ModalScope> { ...@@ -315,12 +315,12 @@ class _ModalScopeState extends State<_ModalScope> {
} }
void dispose() { void dispose() {
config.route.performance?.removeStatusListener(_performanceStatusChanged); config.route.animation?.removeStatusListener(_animationStatusChanged);
config.route.forwardPerformance?.removeStatusListener(_performanceStatusChanged); config.route.forwardAnimation?.removeStatusListener(_animationStatusChanged);
super.dispose(); super.dispose();
} }
void _performanceStatusChanged(PerformanceStatus status) { void _animationStatusChanged(PerformanceStatus status) {
setState(() { setState(() {
// The performances' states are our build state, and they changed already. // The performances' states are our build state, and they changed already.
}); });
...@@ -333,7 +333,7 @@ class _ModalScopeState extends State<_ModalScope> { ...@@ -333,7 +333,7 @@ class _ModalScopeState extends State<_ModalScope> {
child: new _ModalScopeStatus( child: new _ModalScopeStatus(
route: config.route, route: config.route,
isCurrent: config.route.isCurrent, isCurrent: config.route.isCurrent,
child: config.route.buildPage(context, config.route.performance, config.route.forwardPerformance) child: config.route.buildPage(context, config.route.animation, config.route.forwardAnimation)
) )
); );
if (config.route.offstage) { if (config.route.offstage) {
...@@ -342,11 +342,11 @@ class _ModalScopeState extends State<_ModalScope> { ...@@ -342,11 +342,11 @@ class _ModalScopeState extends State<_ModalScope> {
contents = new Focus( contents = new Focus(
key: new GlobalObjectKey(config.route), key: new GlobalObjectKey(config.route),
child: new IgnorePointer( child: new IgnorePointer(
ignoring: config.route.performance?.status == PerformanceStatus.reverse, ignoring: config.route.animation?.status == PerformanceStatus.reverse,
child: config.route.buildTransitions( child: config.route.buildTransitions(
context, context,
config.route.performance, config.route.animation,
config.route.forwardPerformance, config.route.forwardAnimation,
contents contents
) )
) )
...@@ -396,8 +396,8 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T ...@@ -396,8 +396,8 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
// The API for subclasses to override - used by _ModalScope // The API for subclasses to override - used by _ModalScope
ModalPosition getPosition(BuildContext context) => null; ModalPosition getPosition(BuildContext context) => null;
Widget buildPage(BuildContext context, PerformanceView performance, PerformanceView forwardPerformance); Widget buildPage(BuildContext context, Animated<double> animation, Animated<double> forwardAnimation);
Widget buildTransitions(BuildContext context, PerformanceView performance, PerformanceView forwardPerformance, Widget child) { Widget buildTransitions(BuildContext context, Animated<double> animation, Animated<double> forwardAnimation, Widget child) {
return child; return child;
} }
...@@ -442,17 +442,23 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T ...@@ -442,17 +442,23 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
Widget barrier; Widget barrier;
if (barrierColor != null) { if (barrierColor != null) {
assert(barrierColor != _kTransparent); assert(barrierColor != _kTransparent);
Animated<Color> color = new ColorTween(
begin: _kTransparent,
end: barrierColor
).animate(new CurvedAnimation(
parent: animation,
curve: Curves.ease
));
barrier = new AnimatedModalBarrier( barrier = new AnimatedModalBarrier(
color: new AnimatedColorValue(_kTransparent, end: barrierColor, curve: Curves.ease), color: color,
performance: performance,
dismissable: barrierDismissable dismissable: barrierDismissable
); );
} else { } else {
barrier = new ModalBarrier(dismissable: barrierDismissable); barrier = new ModalBarrier(dismissable: barrierDismissable);
} }
assert(performance.status != PerformanceStatus.dismissed); assert(animation.status != PerformanceStatus.dismissed);
return new IgnorePointer( return new IgnorePointer(
ignoring: performance.status == PerformanceStatus.reverse, ignoring: animation.status == PerformanceStatus.reverse,
child: barrier child: barrier
); );
} }
...@@ -470,7 +476,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T ...@@ -470,7 +476,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
_buildModalScope _buildModalScope
]; ];
String toString() => '$runtimeType($settings, performance: $_performance)'; String toString() => '$runtimeType($settings, animation: $_animation)';
} }
/// A modal route that overlays a widget over the current route. /// A modal route that overlays a widget over the current route.
......
...@@ -9,12 +9,12 @@ import 'framework.dart'; ...@@ -9,12 +9,12 @@ import 'framework.dart';
abstract class StatusTransitionComponent extends StatefulComponent { abstract class StatusTransitionComponent extends StatefulComponent {
StatusTransitionComponent({ StatusTransitionComponent({
Key key, Key key,
this.performance this.animation
}) : super(key: key) { }) : super(key: key) {
assert(performance != null); assert(animation != null);
} }
final PerformanceView performance; final Animated<double> animation;
Widget build(BuildContext context); Widget build(BuildContext context);
...@@ -24,18 +24,18 @@ abstract class StatusTransitionComponent extends StatefulComponent { ...@@ -24,18 +24,18 @@ abstract class StatusTransitionComponent extends StatefulComponent {
class _StatusTransitionState extends State<StatusTransitionComponent> { class _StatusTransitionState extends State<StatusTransitionComponent> {
void initState() { void initState() {
super.initState(); super.initState();
config.performance.addStatusListener(_performanceStatusChanged); config.animation.addStatusListener(_performanceStatusChanged);
} }
void didUpdateConfig(StatusTransitionComponent oldConfig) { void didUpdateConfig(StatusTransitionComponent oldConfig) {
if (config.performance != oldConfig.performance) { if (config.animation != oldConfig.animation) {
oldConfig.performance.removeStatusListener(_performanceStatusChanged); oldConfig.animation.removeStatusListener(_performanceStatusChanged);
config.performance.addStatusListener(_performanceStatusChanged); config.animation.addStatusListener(_performanceStatusChanged);
} }
} }
void dispose() { void dispose() {
config.performance.removeStatusListener(_performanceStatusChanged); config.animation.removeStatusListener(_performanceStatusChanged);
super.dispose(); super.dispose();
} }
......
...@@ -63,47 +63,47 @@ class _TransitionState extends State<TransitionComponent> { ...@@ -63,47 +63,47 @@ class _TransitionState extends State<TransitionComponent> {
} }
} }
abstract class AnimationWatchingComponent extends StatefulComponent { abstract class AnimatedComponent extends StatefulComponent {
AnimationWatchingComponent({ AnimatedComponent({
Key key, Key key,
this.watchable this.animation
}) : super(key: key) { }) : super(key: key) {
assert(watchable != null); assert(animation != null);
} }
final Watchable watchable; final Animated<Object> animation;
Widget build(BuildContext context); Widget build(BuildContext context);
_AnimationWatchingComponentState createState() => new _AnimationWatchingComponentState(); _AnimatedComponentState createState() => new _AnimatedComponentState();
void debugFillDescription(List<String> description) { void debugFillDescription(List<String> description) {
super.debugFillDescription(description); super.debugFillDescription(description);
description.add('watchable: $watchable'); description.add('animation: $animation');
} }
} }
class _AnimationWatchingComponentState extends State<AnimationWatchingComponent> { class _AnimatedComponentState extends State<AnimatedComponent> {
void initState() { void initState() {
super.initState(); super.initState();
config.watchable.addListener(_handleTick); config.animation.addListener(_handleTick);
} }
void didUpdateConfig(AnimationWatchingComponent oldConfig) { void didUpdateConfig(AnimatedComponent oldConfig) {
if (config.watchable != oldConfig.watchable) { if (config.animation != oldConfig.animation) {
oldConfig.watchable.removeListener(_handleTick); oldConfig.animation.removeListener(_handleTick);
config.watchable.addListener(_handleTick); config.animation.addListener(_handleTick);
} }
} }
void dispose() { void dispose() {
config.watchable.removeListener(_handleTick); config.animation.removeListener(_handleTick);
super.dispose(); super.dispose();
} }
void _handleTick() { void _handleTick() {
setState(() { setState(() {
// The watchable's state is our build state, and it changed already. // The animation's state is our build state, and it changed already.
}); });
} }
...@@ -146,24 +146,22 @@ class SlideTransition extends TransitionWithChild { ...@@ -146,24 +146,22 @@ class SlideTransition extends TransitionWithChild {
} }
} }
class ScaleTransition extends TransitionWithChild { class ScaleTransition extends AnimatedComponent {
ScaleTransition({ ScaleTransition({
Key key, Key key,
this.scale, Animated<double> scale,
this.alignment: const FractionalOffset(0.5, 0.5), this.alignment: const FractionalOffset(0.5, 0.5),
PerformanceView performance, this.child
Widget child }) : scale = scale, super(key: key, animation: scale);
}) : super(key: key,
performance: performance,
child: child);
final AnimatedValue<double> scale; final Animated<double> scale;
final FractionalOffset alignment; final FractionalOffset alignment;
final Widget child;
Widget buildWithChild(BuildContext context, Widget child) { Widget build(BuildContext context) {
performance.updateVariable(scale); double scaleValue = scale.value;
Matrix4 transform = new Matrix4.identity() Matrix4 transform = new Matrix4.identity()
..scale(scale.value, scale.value); ..scale(scaleValue, scaleValue);
return new Transform( return new Transform(
transform: transform, transform: transform,
alignment: alignment, alignment: alignment,
...@@ -172,21 +170,19 @@ class ScaleTransition extends TransitionWithChild { ...@@ -172,21 +170,19 @@ class ScaleTransition extends TransitionWithChild {
} }
} }
class RotationTransition extends TransitionWithChild { class RotationTransition extends AnimatedComponent {
RotationTransition({ RotationTransition({
Key key, Key key,
this.turns, Animated<double> turns,
PerformanceView performance, this.child
Widget child }) : turns = turns, super(key: key, animation: turns);
}) : super(key: key,
performance: performance,
child: child);
final AnimatedValue<double> turns; final Animated<double> turns;
final Widget child;
Widget buildWithChild(BuildContext context, Widget child) { Widget build(BuildContext context) {
performance.updateVariable(turns); double turnsValue = turns.value;
Matrix4 transform = new Matrix4.rotationZ(turns.value * math.PI * 2.0); Matrix4 transform = new Matrix4.rotationZ(turnsValue * math.PI * 2.0);
return new Transform( return new Transform(
transform: transform, transform: transform,
alignment: const FractionalOffset(0.5, 0.5), alignment: const FractionalOffset(0.5, 0.5),
...@@ -195,8 +191,8 @@ class RotationTransition extends TransitionWithChild { ...@@ -195,8 +191,8 @@ class RotationTransition extends TransitionWithChild {
} }
} }
class FadeTransition extends TransitionWithChild { class OldFadeTransition extends TransitionWithChild {
FadeTransition({ OldFadeTransition({
Key key, Key key,
this.opacity, this.opacity,
PerformanceView performance, PerformanceView performance,
...@@ -213,6 +209,21 @@ class FadeTransition extends TransitionWithChild { ...@@ -213,6 +209,21 @@ class FadeTransition extends TransitionWithChild {
} }
} }
class FadeTransition extends AnimatedComponent {
FadeTransition({
Key key,
Animated<double> opacity,
this.child
}) : opacity = opacity, super(key: key, animation: opacity);
final Animated<double> opacity;
final Widget child;
Widget build(BuildContext context) {
return new Opacity(opacity: opacity.value, child: child);
}
}
class ColorTransition extends TransitionWithChild { class ColorTransition extends TransitionWithChild {
ColorTransition({ ColorTransition({
Key key, Key key,
...@@ -294,9 +305,9 @@ class AlignTransition extends TransitionWithChild { ...@@ -294,9 +305,9 @@ class AlignTransition extends TransitionWithChild {
/// This class specializes the interpolation of AnimatedValue<RelativeRect> to /// This class specializes the interpolation of AnimatedValue<RelativeRect> to
/// be appropriate for rectangles that are described in terms of offsets from /// be appropriate for rectangles that are described in terms of offsets from
/// other rectangles. /// other rectangles.
class AnimatedRelativeRectValue extends AnimatedValue<RelativeRect> { class RelativeRectTween extends Tween<RelativeRect> {
AnimatedRelativeRectValue(RelativeRect begin, { RelativeRect end, Curve curve, Curve reverseCurve }) RelativeRectTween({ RelativeRect begin, RelativeRect end })
: super(begin, end: end, curve: curve, reverseCurve: reverseCurve); : super(begin: begin, end: end);
RelativeRect lerp(double t) => RelativeRect.lerp(begin, end, t); RelativeRect lerp(double t) => RelativeRect.lerp(begin, end, t);
} }
...@@ -307,22 +318,19 @@ class AnimatedRelativeRectValue extends AnimatedValue<RelativeRect> { ...@@ -307,22 +318,19 @@ class AnimatedRelativeRectValue extends AnimatedValue<RelativeRect> {
/// of the performance. /// of the performance.
/// ///
/// Only works if it's the child of a [Stack]. /// Only works if it's the child of a [Stack].
class PositionedTransition extends TransitionWithChild { class PositionedTransition extends AnimatedComponent {
PositionedTransition({ PositionedTransition({
Key key, Key key,
this.rect, Animated<RelativeRect> rect,
PerformanceView performance, this.child
Widget child }) : rect = rect, super(key: key, animation: rect) {
}) : super(key: key,
performance: performance,
child: child) {
assert(rect != null); assert(rect != null);
} }
final AnimatedRelativeRectValue rect; final Animated<RelativeRect> rect;
final Widget child;
Widget buildWithChild(BuildContext context, Widget child) { Widget build(BuildContext context) {
performance.updateVariable(rect);
return new Positioned( return new Positioned(
top: rect.value.top, top: rect.value.top,
right: rect.value.right, right: rect.value.right,
...@@ -352,16 +360,20 @@ class BuilderTransition extends TransitionComponent { ...@@ -352,16 +360,20 @@ class BuilderTransition extends TransitionComponent {
} }
} }
class AnimationWatchingBuilder extends AnimationWatchingComponent { typedef Widget TransitionBuilder(BuildContext context, Widget child);
AnimationWatchingBuilder({
class AnimatedBuilder extends AnimatedComponent {
AnimatedBuilder({
Key key, Key key,
Watchable watchable, Animated<Object> animation,
this.builder this.builder,
}) : super(key: key, watchable: watchable); this.child
}) : super(key: key, animation: animation);
final WidgetBuilder builder; final TransitionBuilder builder;
final Widget child;
Widget build(BuildContext context) { Widget build(BuildContext context) {
return builder(context); return builder(context, child);
} }
} }
...@@ -7,21 +7,22 @@ import 'package:flutter/animation.dart'; ...@@ -7,21 +7,22 @@ import 'package:flutter/animation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test/test.dart' hide TypeMatcher; import 'package:test/test.dart' hide TypeMatcher;
class TestTransition extends TransitionComponent { class TestTransition extends AnimatedComponent {
TestTransition({ TestTransition({
Key key, Key key,
this.childFirstHalf, this.childFirstHalf,
this.childSecondHalf, this.childSecondHalf,
PerformanceView performance Animated<double> animation
}) : super(key: key, performance: performance) { }) : super(key: key, animation: animation) {
assert(performance != null); assert(animation != null);
} }
final Widget childFirstHalf; final Widget childFirstHalf;
final Widget childSecondHalf; final Widget childSecondHalf;
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (performance.progress >= 0.5) final Animated<double> animation = this.animation;
if (animation.value >= 0.5)
return childSecondHalf; return childSecondHalf;
return childFirstHalf; return childFirstHalf;
} }
...@@ -32,7 +33,7 @@ class TestRoute<T> extends PageRoute<T> { ...@@ -32,7 +33,7 @@ class TestRoute<T> extends PageRoute<T> {
final Widget child; final Widget child;
Duration get transitionDuration => kMaterialPageRouteTransitionDuration; Duration get transitionDuration => kMaterialPageRouteTransitionDuration;
Color get barrierColor => null; Color get barrierColor => null;
Widget buildPage(BuildContext context, PerformanceView performance, PerformanceView forwardPerformance) { Widget buildPage(BuildContext context, Animated<double> animation, Animated<double> forwardAnimation) {
return child; return child;
} }
} }
...@@ -81,12 +82,12 @@ void main() { ...@@ -81,12 +82,12 @@ void main() {
new TestTransition( new TestTransition(
childFirstHalf: new Text('A'), childFirstHalf: new Text('A'),
childSecondHalf: new Text('B'), childSecondHalf: new Text('B'),
performance: route.performance animation: route.animation
), ),
new TestTransition( new TestTransition(
childFirstHalf: new Text('C'), childFirstHalf: new Text('C'),
childSecondHalf: new Text('D'), childSecondHalf: new Text('D'),
performance: route.forwardPerformance animation: route.forwardAnimation
), ),
] ]
); );
......
...@@ -13,18 +13,17 @@ void main() { ...@@ -13,18 +13,17 @@ void main() {
test('Can animate position data', () { test('Can animate position data', () {
testWidgets((WidgetTester tester) { testWidgets((WidgetTester tester) {
final AnimatedRelativeRectValue rect = new AnimatedRelativeRectValue( final RelativeRectTween rect = new RelativeRectTween(
new RelativeRect.fromRect( begin: new RelativeRect.fromRect(
new Rect.fromLTRB(10.0, 20.0, 20.0, 30.0), new Rect.fromLTRB(10.0, 20.0, 20.0, 30.0),
new Rect.fromLTRB(0.0, 10.0, 100.0, 110.0) new Rect.fromLTRB(0.0, 10.0, 100.0, 110.0)
), ),
end: new RelativeRect.fromRect( end: new RelativeRect.fromRect(
new Rect.fromLTRB(80.0, 90.0, 90.0, 100.0), new Rect.fromLTRB(80.0, 90.0, 90.0, 100.0),
new Rect.fromLTRB(0.0, 10.0, 100.0, 110.0) new Rect.fromLTRB(0.0, 10.0, 100.0, 110.0)
), )
curve: Curves.linear
); );
final Performance performance = new Performance( final AnimationController controller = new AnimationController(
duration: const Duration(seconds: 10) duration: const Duration(seconds: 10)
); );
final List<Size> sizes = <Size>[]; final List<Size> sizes = <Size>[];
...@@ -46,8 +45,7 @@ void main() { ...@@ -46,8 +45,7 @@ void main() {
child: new Stack( child: new Stack(
children: <Widget>[ children: <Widget>[
new PositionedTransition( new PositionedTransition(
rect: rect, rect: rect.animate(controller),
performance: performance,
child: new Container( child: new Container(
key: key key: key
) )
...@@ -58,7 +56,7 @@ void main() { ...@@ -58,7 +56,7 @@ void main() {
) )
); // t=0 ); // t=0
recordMetrics(); recordMetrics();
performance.play(); controller.forward();
tester.pump(); // t=0 again tester.pump(); // t=0 again
recordMetrics(); recordMetrics();
tester.pump(const Duration(seconds: 1)); // t=1 tester.pump(const Duration(seconds: 1)); // t=1
......
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