Give Interval a Curve to apply between start and end This patch simplifies AnimationTiming and all the AnimatedValue base classes. Also, make PopupMenu a stateless component because it has no state. Fixes #1168
diff --git a/examples/widgets/progress_indicator.dart b/examples/widgets/progress_indicator.dart index e769784..b4b2b41 100644 --- a/examples/widgets/progress_indicator.dart +++ b/examples/widgets/progress_indicator.dart
@@ -18,9 +18,8 @@ ..variable = new AnimatedValue<double>( 0.0, end: 1.0, - curve: ease, - reverseCurve: ease, - interval: new Interval(0.0, 0.9) + curve: new Interval(0.0, 0.9, curve: ease), + reverseCurve: ease ); valueAnimation.addStatusListener((PerformanceStatus status) { if (status == PerformanceStatus.dismissed || status == PerformanceStatus.completed)
diff --git a/packages/flutter/lib/src/animation/animated_value.dart b/packages/flutter/lib/src/animation/animated_value.dart index f42c4b8..9b4a8da 100644 --- a/packages/flutter/lib/src/animation/animated_value.dart +++ b/packages/flutter/lib/src/animation/animated_value.dart
@@ -25,70 +25,43 @@ String toString(); } -/// Used by [AnimationPerformance] to convert the timing of a performance to a different timescale. +/// Used by [Performance] to convert the timing of a performance to a different timescale. /// For example, by setting different values for the interval and reverseInterval, a performance /// can be made to take longer in one direction that the other. class AnimationTiming { - AnimationTiming({ - this.interval: const Interval(0.0, 1.0), - this.reverseInterval, - this.curve: linear, - this.reverseCurve - }); + AnimationTiming({ this.curve, this.reverseCurve }); - /// The interval during which this timing is active in the forward direction - Interval interval; - - /// The interval during which this timing is active in the reverse direction - /// - /// If this field is null, the timing defaults to using [interval] in both directions. - Interval reverseInterval; - - /// The curve that this timing applies to the animation clock in the forward direction + /// The curve to use in the forward direction Curve curve; - /// The curve that this timing applies to the animation clock in the reverse direction + /// The curve to use in the reverse direction /// - /// If this field is null, the timing defaults to using [curve] in both directions. + /// If this field is null, use [curve] in both directions. Curve reverseCurve; /// Applies this timing to the given animation clock value in the given direction double transform(double t, AnimationDirection direction) { - Interval interval = _getInterval(direction); - if (interval != null) - t = interval.transform(t); - assert(t >= 0.0 && t <= 1.0); + Curve activeCurve = _getActiveCurve(direction); + if (activeCurve == null) + return t; if (t == 0.0 || t == 1.0) { - assert(t == _applyCurve(t, direction).round().toDouble()); + assert(activeCurve.transform(t).round() == t); return t; } - return _applyCurve(t, direction); + return activeCurve.transform(t); } - Interval _getInterval(AnimationDirection direction) { - if (direction == AnimationDirection.forward || reverseInterval == null) - return interval; - return reverseInterval; - } - - Curve _getCurve(AnimationDirection direction) { + Curve _getActiveCurve(AnimationDirection direction) { if (direction == AnimationDirection.forward || reverseCurve == null) return curve; return reverseCurve; } - - double _applyCurve(double t, AnimationDirection direction) { - Curve curve = _getCurve(direction); - if (curve == null) - return t; - return curve.transform(t); - } } /// An animated variable with a concrete type class AnimatedValue<T extends dynamic> extends AnimationTiming implements Animatable { - AnimatedValue(this.begin, { this.end, Interval interval, Interval reverseInterval, Curve curve, Curve reverseCurve }) - : super(interval: interval, reverseInterval: reverseInterval, curve: curve, reverseCurve: reverseCurve) { + AnimatedValue(this.begin, { this.end, Curve curve, Curve reverseCurve }) + : super(curve: curve, reverseCurve: reverseCurve) { value = begin; } @@ -125,8 +98,8 @@ /// This class specializes the interpolation of AnimatedValue<Color> to be /// appropriate for colors. class AnimatedColorValue extends AnimatedValue<Color> { - AnimatedColorValue(Color begin, { Color end, Interval interval, Interval reverseInterval, Curve curve, Curve reverseCurve }) - : super(begin, end: end, interval: interval, reverseInterval: reverseInterval, curve: curve, reverseCurve: reverseCurve); + AnimatedColorValue(Color begin, { Color end, Curve curve, Curve reverseCurve }) + : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); Color lerp(double t) => Color.lerp(begin, end, t); } @@ -136,8 +109,8 @@ /// This class specializes the interpolation of AnimatedValue<Rect> to be /// appropriate for rectangles. class AnimatedRectValue extends AnimatedValue<Rect> { - AnimatedRectValue(Rect begin, { Rect end, Interval interval, Interval reverseInterval, Curve curve, Curve reverseCurve }) - : super(begin, end: end, interval: interval, reverseInterval: reverseInterval, curve: curve, reverseCurve: reverseCurve); + AnimatedRectValue(Rect begin, { Rect end, Curve curve, Curve reverseCurve }) + : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); Rect lerp(double t) => Rect.lerp(begin, end, t); }
diff --git a/packages/flutter/lib/src/animation/curves.dart b/packages/flutter/lib/src/animation/curves.dart index 31fb4a9..5b44cc4 100644 --- a/packages/flutter/lib/src/animation/curves.dart +++ b/packages/flutter/lib/src/animation/curves.dart
@@ -27,9 +27,9 @@ double transform(double t) => t; } -/// A curve that is 0.0 until start, then linear from 0.0 to 1.0 at end, then 1.0 +/// A curve that is 0.0 until start, then curved from 0.0 to 1.0 at end, then 1.0 class Interval implements Curve { - const Interval(this.start, this.end); + const Interval(this.start, this.end, { this.curve: linear }); /// The smallest value for which this interval is 0.0 final double start; @@ -37,12 +37,18 @@ /// The smallest value for which this interval is 1.0 final double end; + /// The curve to apply between [start] and [end] + final Curve curve; + double transform(double t) { assert(start >= 0.0); assert(start <= 1.0); assert(end >= 0.0); assert(end <= 1.0); - return ((t - start) / (end - start)).clamp(0.0, 1.0); + t = ((t - start) / (end - start)).clamp(0.0, 1.0); + if (t == 0.0 || t == 1.0) + return t; + return curve.transform(t); } }
diff --git a/packages/flutter/lib/src/widgets/animated_container.dart b/packages/flutter/lib/src/widgets/animated_container.dart index 4d1f1d4..e9c56a1 100644 --- a/packages/flutter/lib/src/widgets/animated_container.dart +++ b/packages/flutter/lib/src/widgets/animated_container.dart
@@ -9,29 +9,29 @@ import 'package:vector_math/vector_math_64.dart'; class AnimatedBoxConstraintsValue extends AnimatedValue<BoxConstraints> { - AnimatedBoxConstraintsValue(BoxConstraints begin, { BoxConstraints end, Curve curve: linear }) - : super(begin, end: end, curve: curve); + AnimatedBoxConstraintsValue(BoxConstraints begin, { BoxConstraints end, Curve curve, Curve reverseCurve }) + : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); BoxConstraints lerp(double t) => BoxConstraints.lerp(begin, end, t); } class AnimatedBoxDecorationValue extends AnimatedValue<BoxDecoration> { - AnimatedBoxDecorationValue(BoxDecoration begin, { BoxDecoration end, Curve curve: linear }) - : super(begin, end: end, curve: curve); + AnimatedBoxDecorationValue(BoxDecoration begin, { BoxDecoration end, Curve curve, Curve reverseCurve }) + : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); BoxDecoration lerp(double t) => BoxDecoration.lerp(begin, end, t); } class AnimatedEdgeDimsValue extends AnimatedValue<EdgeDims> { - AnimatedEdgeDimsValue(EdgeDims begin, { EdgeDims end, Curve curve: linear }) - : super(begin, end: end, curve: curve); + AnimatedEdgeDimsValue(EdgeDims begin, { EdgeDims end, Curve curve, Curve reverseCurve }) + : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); EdgeDims lerp(double t) => EdgeDims.lerp(begin, end, t); } class AnimatedMatrix4Value extends AnimatedValue<Matrix4> { - AnimatedMatrix4Value(Matrix4 begin, { Matrix4 end, Curve curve: linear }) - : super(begin, end: end, curve: curve); + AnimatedMatrix4Value(Matrix4 begin, { Matrix4 end, Curve curve, Curve reverseCurve }) + : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); Matrix4 lerp(double t) { // TODO(mpcomplete): Animate the full matrix. Will animating the cells
diff --git a/packages/flutter/lib/src/widgets/dismissable.dart b/packages/flutter/lib/src/widgets/dismissable.dart index d019580..b9c11e2 100644 --- a/packages/flutter/lib/src/widgets/dismissable.dart +++ b/packages/flutter/lib/src/widgets/dismissable.dart
@@ -12,7 +12,7 @@ const Duration _kCardDismissFadeout = const Duration(milliseconds: 200); const Duration _kCardDismissResize = const Duration(milliseconds: 300); -final Interval _kCardDismissResizeInterval = new Interval(0.4, 1.0); +const Curve _kCardDismissResizeCurve = const Interval(0.4, 1.0, curve: ease); const double _kMinFlingVelocity = 700.0; const double _kMinFlingVelocityDelta = 400.0; const double _kFlingVelocityScale = 1.0 / 300.0; @@ -226,8 +226,7 @@ AnimatedValue<double> squashAxisExtent = new AnimatedValue<double>( _directionIsYAxis ? _size.width : _size.height, end: 0.0, - curve: ease, - interval: _kCardDismissResizeInterval + curve: _kCardDismissResizeCurve ); return new SquashTransition(
diff --git a/packages/flutter/lib/src/widgets/popup_menu.dart b/packages/flutter/lib/src/widgets/popup_menu.dart index 3812fb7..c6af624 100644 --- a/packages/flutter/lib/src/widgets/popup_menu.dart +++ b/packages/flutter/lib/src/widgets/popup_menu.dart
@@ -29,7 +29,7 @@ typedef List<PopupMenuItem> PopupMenuItemsBuilder(NavigatorState navigator); -class PopupMenu extends StatefulComponent { +class PopupMenu extends StatelessComponent { PopupMenu({ Key key, this.items, @@ -46,76 +46,46 @@ final NavigatorState navigator; final PerformanceView performance; - PopupMenuState createState() => new PopupMenuState(); -} - -class PopupMenuState extends State<PopupMenu> { - void initState() { - super.initState(); - config.performance.addListener(_performanceChanged); - } - - void didUpdateConfig(PopupMenu oldConfig) { - if (config.performance != oldConfig.performance) { - oldConfig.performance.removeListener(_performanceChanged); - config.performance.addListener(_performanceChanged); - } - } - - void dispose() { - config.performance.removeListener(_performanceChanged); - super.dispose(); - } - - void _performanceChanged() { - setState(() { - // the performance changed, and our state is tied up with the performance - }); - } - - BoxPainter _painter; - - void _updateBoxPainter(BoxDecoration decoration) { - if (_painter == null || _painter.decoration != decoration) - _painter = new BoxPainter(decoration); - } - Widget build(BuildContext context) { - _updateBoxPainter(new BoxDecoration( + final BoxPainter painter = new BoxPainter(new BoxDecoration( backgroundColor: Theme.of(context).canvasColor, borderRadius: 2.0, - boxShadow: shadows[config.level] + boxShadow: shadows[level] )); - double unit = 1.0 / (config.items.length + 1.5); // 1.0 for the width and 0.5 for the last item's fade. + + double unit = 1.0 / (items.length + 1.5); // 1.0 for the width and 0.5 for the last item's fade. List<Widget> children = []; - for (int i = 0; i < config.items.length; ++i) { + + for (int i = 0; i < items.length; ++i) { double start = (i + 1) * unit; double end = (start + 1.5 * unit).clamp(0.0, 1.0); children.add(new FadeTransition( - performance: config.performance, - opacity: new AnimatedValue<double>(0.0, end: 1.0, interval: new Interval(start, end)), + performance: performance, + opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(start, end)), child: new InkWell( - onTap: () { config.navigator.pop(config.items[i].value); }, - child: config.items[i] + onTap: () { navigator.pop(items[i].value); }, + child: items[i] )) ); } - final width = new AnimatedValue<double>(0.0, end: 1.0, interval: new Interval(0.0, unit)); - final height = new AnimatedValue<double>(0.0, end: 1.0, interval: new Interval(0.0, unit * config.items.length)); + + final width = new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(0.0, unit)); + final height = new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(0.0, unit * items.length)); + return new FadeTransition( - performance: config.performance, - opacity: new AnimatedValue<double>(0.0, end: 1.0, interval: new Interval(0.0, 1.0 / 3.0)), + performance: performance, + opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(0.0, 1.0 / 3.0)), child: new Container( margin: new EdgeDims.all(_kMenuMargin), child: new BuilderTransition( - performance: config.performance, + performance: performance, variables: [width, height], builder: (BuildContext context) { return new CustomPaint( callback: (sky.Canvas canvas, Size size) { double widthValue = width.value * size.width; double heightValue = height.value * size.height; - _painter.paint(canvas, new Rect.fromLTWH(size.width - widthValue, 0.0, widthValue, heightValue)); + painter.paint(canvas, new Rect.fromLTWH(size.width - widthValue, 0.0, widthValue, heightValue)); }, child: new ConstrainedBox( constraints: new BoxConstraints( @@ -162,7 +132,7 @@ Performance createPerformance() { Performance result = super.createPerformance(); AnimationTiming timing = new AnimationTiming(); - timing.reverseInterval = new Interval(0.0, _kMenuCloseIntervalEnd); + timing.reverseCurve = new Interval(0.0, _kMenuCloseIntervalEnd); result.timing = timing; return result; }