diff --git a/examples/widgets/progress_indicator.dart b/examples/widgets/progress_indicator.dart index e769784b46..b4b2b410a1 100644 --- a/examples/widgets/progress_indicator.dart +++ b/examples/widgets/progress_indicator.dart @@ -18,9 +18,8 @@ class ProgressIndicatorAppState extends State { ..variable = new AnimatedValue( 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 f42c4b8910..9b4a8daa1b 100644 --- a/packages/flutter/lib/src/animation/animated_value.dart +++ b/packages/flutter/lib/src/animation/animated_value.dart @@ -25,70 +25,43 @@ abstract class Animatable { 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 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 @@ class AnimatedValue extends AnimationTiming implements Animat /// This class specializes the interpolation of AnimatedValue to be /// appropriate for colors. class AnimatedColorValue extends AnimatedValue { - 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 @@ class AnimatedColorValue extends AnimatedValue { /// This class specializes the interpolation of AnimatedValue to be /// appropriate for rectangles. class AnimatedRectValue extends AnimatedValue { - 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 31fb4a911b..5b44cc43eb 100644 --- a/packages/flutter/lib/src/animation/curves.dart +++ b/packages/flutter/lib/src/animation/curves.dart @@ -27,9 +27,9 @@ class Linear implements Curve { 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 @@ class Interval implements Curve { /// 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 4d1f1d4de0..e9c56a115a 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:sky/src/widgets/framework.dart'; import 'package:vector_math/vector_math_64.dart'; class AnimatedBoxConstraintsValue extends AnimatedValue { - 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 { - 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 { - 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 { - 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 d019580a68..b9c11e2ecf 100644 --- a/packages/flutter/lib/src/widgets/dismissable.dart +++ b/packages/flutter/lib/src/widgets/dismissable.dart @@ -12,7 +12,7 @@ import 'package:sky/src/widgets/gesture_detector.dart'; 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 @@ class DismissableState extends State { AnimatedValue squashAxisExtent = new AnimatedValue( _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 3812fb779a..c6af624244 100644 --- a/packages/flutter/lib/src/widgets/popup_menu.dart +++ b/packages/flutter/lib/src/widgets/popup_menu.dart @@ -29,7 +29,7 @@ const double _kMenuVerticalPadding = 8.0; typedef List PopupMenuItemsBuilder(NavigatorState navigator); -class PopupMenu extends StatefulComponent { +class PopupMenu extends StatelessComponent { PopupMenu({ Key key, this.items, @@ -46,76 +46,46 @@ class PopupMenu extends StatefulComponent { final NavigatorState navigator; final PerformanceView performance; - PopupMenuState createState() => new PopupMenuState(); -} - -class PopupMenuState extends State { - 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 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(0.0, end: 1.0, interval: new Interval(start, end)), + performance: performance, + opacity: new AnimatedValue(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(0.0, end: 1.0, interval: new Interval(0.0, unit)); - final height = new AnimatedValue(0.0, end: 1.0, interval: new Interval(0.0, unit * config.items.length)); + + final width = new AnimatedValue(0.0, end: 1.0, curve: new Interval(0.0, unit)); + final height = new AnimatedValue(0.0, end: 1.0, curve: new Interval(0.0, unit * items.length)); + return new FadeTransition( - performance: config.performance, - opacity: new AnimatedValue(0.0, end: 1.0, interval: new Interval(0.0, 1.0 / 3.0)), + performance: performance, + opacity: new AnimatedValue(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 @@ class MenuRoute extends Route { 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; }