diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index 2effaf7dbc4..c6701d47a5a 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -28,7 +28,7 @@ const double _kMenuVerticalPadding = 8.0; const double _kMenuWidthStep = 56.0; const double _kMenuScreenPadding = 8.0; -abstract class PopupMenuEntry extends StatelessComponent { +abstract class PopupMenuEntry extends StatefulComponent { PopupMenuEntry({ Key key }) : super(key: key); double get height; @@ -41,7 +41,11 @@ class PopupMenuDivider extends PopupMenuEntry { final double height; - Widget build(BuildContext context) => new Divider(height: height); + _PopupMenuDividerState createState() => new _PopupMenuDividerState(); +} + +class _PopupMenuDividerState extends State { + Widget build(BuildContext context) => new Divider(height: config.height); } class PopupMenuItem extends PopupMenuEntry { @@ -58,20 +62,31 @@ class PopupMenuItem extends PopupMenuEntry { double get height => _kMenuItemHeight; + _PopupMenuItemState> createState() => new _PopupMenuItemState>(); +} + +class _PopupMenuItemState extends State { + // Override this to put something else in the menu entry. + Widget buildChild() => config.child; + + void onTap() { + Navigator.pop(context, config.value); + } + Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); TextStyle style = theme.text.subhead; - if (!enabled) + if (!config.enabled) style = style.copyWith(color: theme.disabledColor); Widget item = new DefaultTextStyle( style: style, child: new Baseline( - baseline: height - _kBaselineOffsetFromBottom, - child: child + baseline: config.height - _kBaselineOffsetFromBottom, + child: buildChild() ) ); - if (!enabled) { + if (!config.enabled) { final bool isDark = theme.brightness == ThemeBrightness.dark; item = new IconTheme( data: new IconThemeData(opacity: isDark ? 0.5 : 0.38), @@ -79,11 +94,14 @@ class PopupMenuItem extends PopupMenuEntry { ); } - return new MergeSemantics( - child: new Container( - height: height, - padding: const EdgeDims.symmetric(horizontal: _kMenuHorizontalPadding), - child: item + return new InkWell( + onTap: config.enabled ? onTap : null, + child: new MergeSemantics( + child: new Container( + height: config.height, + padding: const EdgeDims.symmetric(horizontal: _kMenuHorizontalPadding), + child: item + ) ) ); } @@ -93,19 +111,52 @@ class CheckedPopupMenuItem extends PopupMenuItem { CheckedPopupMenuItem({ Key key, T value, - checked: false, + this.checked: false, bool enabled: true, Widget child }) : super( key: key, value: value, enabled: enabled, - child: new ListItem( - enabled: enabled, - left: new Icon(icon: checked ? Icons.done : null), - primary: child - ) + child: child ); + + final bool checked; + + _CheckedPopupMenuItemState createState() => new _CheckedPopupMenuItemState(); +} + +class _CheckedPopupMenuItemState extends _PopupMenuItemState> { + static const Duration _kFadeDuration = const Duration(milliseconds: 150); + AnimationController _controller; + Animation get _opacity => _controller.view; + + void initState() { + super.initState(); + _controller = new AnimationController(duration: _kFadeDuration) + ..value = config.checked ? 1.0 : 0.0 + ..addListener(() => setState(() { /* animation changed */ })); + } + + void onTap() { + // This fades the checkmark in or out when tapped. + if (config.checked) + _controller.reverse(); + else + _controller.forward(); + super.onTap(); + } + + Widget buildChild() { + return new ListItem( + enabled: config.enabled, + left: new FadeTransition( + opacity: _opacity, + child: new Icon(icon: _controller.isDismissed ? null : Icons.done) + ), + primary: config.child + ); + } } class _PopupMenu extends StatelessComponent { @@ -127,7 +178,6 @@ class _PopupMenu extends StatelessComponent { parent: route.animation, curve: new Interval(start, end) ); - final bool enabled = route.items[i].enabled; Widget item = route.items[i]; if (route.initialValue != null && route.initialValue == route.items[i].value) { item = new Container( @@ -137,10 +187,7 @@ class _PopupMenu extends StatelessComponent { } children.add(new FadeTransition( opacity: opacity, - child: new InkWell( - onTap: enabled ? () { Navigator.pop(context, route.items[i].value); } : null, - child: item - ) + child: item )); }