diff --git a/packages/flutter/lib/src/animation/animations.dart b/packages/flutter/lib/src/animation/animations.dart index f2eb3ee7e0..45442315e2 100644 --- a/packages/flutter/lib/src/animation/animations.dart +++ b/packages/flutter/lib/src/animation/animations.dart @@ -300,8 +300,8 @@ class ReverseAnimation extends Animation /// [CurvedAnimation] is useful when you want to apply a non-linear [Curve] to /// an animation object wrapped in the [CurvedAnimation]. /// -/// For example, the following code snippet shows how you can apply a curve to a linear animation -/// produced by an [AnimationController]: +/// For example, the following code snippet shows how you can apply a curve to a +/// linear animation produced by an [AnimationController]: /// /// ``` dart /// final AnimationController controller = @@ -309,9 +309,10 @@ class ReverseAnimation extends Animation /// final CurvedAnimation animation = /// new CurvedAnimation(parent: controller, curve: Curves.ease); ///``` -/// Depending on the given curve, the output of the [CurvedAnimation] could have a wider range -/// than its input. For example, elastic curves such as [Curves.elasticIn] will significantly -/// overshoot or undershoot the default range of 0.0 to 1.0. +/// Depending on the given curve, the output of the [CurvedAnimation] could have +/// a wider range than its input. For example, elastic curves such as +/// [Curves.elasticIn] will significantly overshoot or undershoot the default +/// range of 0.0 to 1.0. /// /// If you want to apply a [Curve] to a [Tween], consider using [CurveTween]. class CurvedAnimation extends Animation with AnimationWithParentMixin { @@ -325,7 +326,8 @@ class CurvedAnimation extends Animation with AnimationWithParentMixin with AnimationWithParentMixin with AnimationWithParentMixin extends StatusTransitionWidget { +class _DropDownMenu extends StatefulWidget { _DropDownMenu({ Key key, _DropDownRoute route - }) : route = route, super(key: key, animation: route.animation); + }) : route = route, super(key: key); final _DropDownRoute route; + @override + _DropDownMenuState createState() => new _DropDownMenuState(); +} + +class _DropDownMenuState extends State<_DropDownMenu> { + CurvedAnimation _fadeOpacity; + CurvedAnimation _resize; + + @override + void initState() { + super.initState(); + // We need to hold these animations as state because of their curve + // direction. When the route's animation reverses, if we were to recreate + // the CurvedAnimation objects in build, we'd lose + // CurvedAnimation._curveDirection. + _fadeOpacity = new CurvedAnimation( + parent: config.route.animation, + curve: const Interval(0.0, 0.25), + reverseCurve: const Interval(0.75, 1.0) + ); + _resize = new CurvedAnimation( + parent: config.route.animation, + curve: const Interval(0.25, 0.5), + reverseCurve: const Step(0.0) + ); + } + @override Widget build(BuildContext context) { // The menu is shown in three stages (unit timing in brackets): @@ -89,17 +116,17 @@ class _DropDownMenu extends StatusTransitionWidget { // When the menu is dismissed we just fade the entire thing out // in the first 0.25s. + final _DropDownRoute route = config.route; final double unit = 0.5 / (route.items.length + 1.5); final List children = []; for (int itemIndex = 0; itemIndex < route.items.length; ++itemIndex) { CurvedAnimation opacity; - Interval reverseCurve = const Interval(0.75, 1.0); if (itemIndex == route.selectedIndex) { - opacity = new CurvedAnimation(parent: route.animation, curve: const Step(0.0), reverseCurve: reverseCurve); + opacity = new CurvedAnimation(parent: route.animation, curve: const Step(0.0)); } else { 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); - opacity = new CurvedAnimation(parent: route.animation, curve: new Interval(start, end), reverseCurve: reverseCurve); + opacity = new CurvedAnimation(parent: route.animation, curve: new Interval(start, end)); } children.add(new FadeTransition( opacity: opacity, @@ -117,21 +144,13 @@ class _DropDownMenu extends StatusTransitionWidget { } return new FadeTransition( - opacity: new CurvedAnimation( - parent: route.animation, - curve: const Interval(0.0, 0.25), - reverseCurve: const Interval(0.75, 1.0) - ), + opacity: _fadeOpacity, child: new CustomPaint( painter: new _DropDownMenuPainter( color: Theme.of(context).canvasColor, elevation: route.elevation, selectedIndex: route.selectedIndex, - resize: new CurvedAnimation( - parent: route.animation, - curve: const Interval(0.25, 0.5), - reverseCurve: const Step(0.0) - ) + resize: _resize ), child: new Material( type: MaterialType.transparency, @@ -456,8 +475,7 @@ class _DropDownButtonState extends State> { Widget build(BuildContext context) { assert(debugCheckHasMaterial(context)); final TextStyle style = _textStyle; - if (_currentRoute != null) - _currentRoute.style = style; + _currentRoute?.style = style; Widget result = new DefaultTextStyle( style: style, child: new Row(