Index: sky/framework/components/popup_menu.dart |
diff --git a/sky/framework/components/popup_menu.dart b/sky/framework/components/popup_menu.dart |
index 18996b75c2dfd88cb19b9ea1bf1226c7a2c23194..c3bf1afb15598b0dda0887511c17aa5c9cf3c3bd 100644 |
--- a/sky/framework/components/popup_menu.dart |
+++ b/sky/framework/components/popup_menu.dart |
@@ -7,14 +7,14 @@ import '../animation/animated_value.dart'; |
import '../fn.dart'; |
import '../theme/colors.dart'; |
import '../theme/view-configuration.dart'; |
+import 'dart:async'; |
import 'dart:math' as math; |
import 'dart:sky' as sky; |
import 'material.dart'; |
import 'popup_menu_item.dart'; |
-const double _kItemFadeDuration = 300.0; |
-const double _kItemFadeDelay = 100.0; |
-const double _kMenuExpandDuration = 300.0; |
+const double _kMenuOpenDuration = 300.0; |
+const double _kMenuCloneDuration = 200.0; |
class PopupMenuController { |
bool isOpen = false; |
@@ -22,14 +22,13 @@ class PopupMenuController { |
void open() { |
isOpen = true; |
- position.animateTo(1.0, _kMenuExpandDuration); |
+ position.animateTo(1.0, _kMenuOpenDuration); |
} |
- void close() { |
- position.animateTo(0.0, _kMenuExpandDuration); |
- // TODO(abarth): We shouldn't mark the menu as closed until the animation |
- // completes. |
- isOpen = false; |
+ Future close() { |
+ return position.animateTo(0.0, _kMenuCloneDuration).then((_) { |
+ isOpen = false; |
+ }); |
} |
} |
@@ -45,35 +44,32 @@ class PopupMenu extends AnimatedComponent { |
PopupMenuController controller; |
double _position; |
- List<AnimatedValue> _opacities; |
int _width; |
int _height; |
PopupMenu({ Object key, this.controller, this.items, this.level }) |
: super(key: key) { |
animateField(controller.position, #_position); |
- |
onDidMount(_measureSize); |
} |
- void _ensureItemAnimations() { |
- if (_opacities != null && controller.isOpen) |
- return; |
- _opacities = new List.from(items.map((_) => new AnimatedValue(0.0))); |
- int i = 0; |
- _opacities.forEach((opacity) { |
- opacity.animateTo(1.0, _kItemFadeDuration, |
- initialDelay: _kItemFadeDelay * ++i); |
- }); |
+ double _opacityFor(int i) { |
+ if (_position == null || _position == 1.0) |
+ return null; |
+ double unit = 1.0 / items.length; |
+ double duration = 1.5 * unit; |
+ double start = i * unit; |
+ return math.max(0.0, math.min(1.0, (_position - start) / duration)); |
} |
String _inlineStyle() { |
- if (_position == null || _position == 1.0 || _height == null || _width == null) |
+ if (_position == null || _position == 1.0 || |
+ _height == null || _width == null) |
return null; |
return ''' |
- opacity: ${math.min(1.0, _position * 1.5)}; |
- width: ${math.min(_width, _width * _position * 3.0)}px; |
- height: ${_height * _position}px;'''; |
+ opacity: ${math.min(1.0, _position * 3.0)}; |
+ width: ${math.min(_width, _width * (0.5 + _position * 2.0))}px; |
+ height: ${math.min(_height, _height * _position * 1.5)}px;'''; |
} |
void _measureSize() { |
@@ -85,24 +81,16 @@ class PopupMenu extends AnimatedComponent { |
} |
Node build() { |
- _ensureItemAnimations(); |
- |
- List<Node> children = []; |
- |
- if (controller.isOpen) { |
- int i = 0; |
- items.forEach((List<Node> item) { |
- children.add( |
- new PopupMenuItem(key: i, children: item, opacity: _opacities[i])); |
- ++i; |
- }); |
- } |
+ int i = 0; |
+ List<Node> children = new List.from(items.map((List<Node> item) { |
+ double opacity = _opacityFor(i); |
+ return new PopupMenuItem(key: i++, children: item, opacity: opacity); |
+ })); |
return new Material( |
style: _style, |
inlineStyle: _inlineStyle(), |
children: children, |
- level: level |
- ); |
+ level: level); |
} |
} |