mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
PopupMenuButton should lazily build menu items
Previously, the client of PopupMenuButton needed to build all the menu times when building the PopupMenuButton. This can get expensive if, for example, each item in a scrollable list has a popup menu associated with it. Now the client passes a builder function to the PopupMenuButton that gets invoked only when its time to show the menu items.
This commit is contained in:
parent
b930f0d4ff
commit
7ab122e557
@ -101,7 +101,7 @@ class TopBarMenu extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return new PopupMenuButton<String>(
|
return new PopupMenuButton<String>(
|
||||||
onSelected: (String value) { print("Selected: $value"); },
|
onSelected: (String value) { print("Selected: $value"); },
|
||||||
items: <PopupMenuItem<String>>[
|
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
|
||||||
new PopupMenuItem<String>(
|
new PopupMenuItem<String>(
|
||||||
value: "Friends",
|
value: "Friends",
|
||||||
child: new MenuItemWithIcon(Icons.people, "Friends", "5 new")
|
child: new MenuItemWithIcon(Icons.people, "Friends", "5 new")
|
||||||
|
@ -110,7 +110,7 @@ class FlexibleSpaceDemoState extends State<FlexibleSpaceDemo> {
|
|||||||
_appBarBehavior = value;
|
_appBarBehavior = value;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
items: <PopupMenuItem<AppBarBehavior>>[
|
itemBuilder: (BuildContext context) => <PopupMenuItem<AppBarBehavior>>[
|
||||||
new PopupMenuItem<AppBarBehavior>(
|
new PopupMenuItem<AppBarBehavior>(
|
||||||
value: AppBarBehavior.scroll,
|
value: AppBarBehavior.scroll,
|
||||||
child: new Text('AppBar scrolls away')
|
child: new Text('AppBar scrolls away')
|
||||||
|
@ -134,7 +134,7 @@ class LeaveBehindDemoState extends State<LeaveBehindDemo> {
|
|||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
new PopupMenuButton<LeaveBehindDemoAction>(
|
new PopupMenuButton<LeaveBehindDemoAction>(
|
||||||
onSelected: handleDemoAction,
|
onSelected: handleDemoAction,
|
||||||
items: <PopupMenuEntry<LeaveBehindDemoAction>>[
|
itemBuilder: (BuildContext context) => <PopupMenuEntry<LeaveBehindDemoAction>>[
|
||||||
new PopupMenuItem<LeaveBehindDemoAction>(
|
new PopupMenuItem<LeaveBehindDemoAction>(
|
||||||
value: LeaveBehindDemoAction.reset,
|
value: LeaveBehindDemoAction.reset,
|
||||||
child: new Text('Reset the list')
|
child: new Text('Reset the list')
|
||||||
|
@ -64,7 +64,7 @@ class MenuDemoState extends State<MenuDemo> {
|
|||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
new PopupMenuButton<String>(
|
new PopupMenuButton<String>(
|
||||||
onSelected: showMenuSelection,
|
onSelected: showMenuSelection,
|
||||||
items: <PopupMenuItem<String>>[
|
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
|
||||||
new PopupMenuItem<String>(
|
new PopupMenuItem<String>(
|
||||||
value: 'AppBar Menu',
|
value: 'AppBar Menu',
|
||||||
child: new Text('AppBar Menu')
|
child: new Text('AppBar Menu')
|
||||||
@ -91,7 +91,7 @@ class MenuDemoState extends State<MenuDemo> {
|
|||||||
title: new Text('An item with a context menu button'),
|
title: new Text('An item with a context menu button'),
|
||||||
trailing: new PopupMenuButton<String>(
|
trailing: new PopupMenuButton<String>(
|
||||||
onSelected: showMenuSelection,
|
onSelected: showMenuSelection,
|
||||||
items: <PopupMenuItem<String>>[
|
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
|
||||||
new PopupMenuItem<String>(
|
new PopupMenuItem<String>(
|
||||||
value: _simpleValue1,
|
value: _simpleValue1,
|
||||||
child: new Text('Context menu item one')
|
child: new Text('Context menu item one')
|
||||||
@ -114,7 +114,7 @@ class MenuDemoState extends State<MenuDemo> {
|
|||||||
title: new Text('An item with a sectioned menu'),
|
title: new Text('An item with a sectioned menu'),
|
||||||
trailing: new PopupMenuButton<String>(
|
trailing: new PopupMenuButton<String>(
|
||||||
onSelected: showMenuSelection,
|
onSelected: showMenuSelection,
|
||||||
items: <PopupMenuEntry<String>>[
|
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
|
||||||
new PopupMenuItem<String>(
|
new PopupMenuItem<String>(
|
||||||
value: 'Preview',
|
value: 'Preview',
|
||||||
child: new ListItem(
|
child: new ListItem(
|
||||||
@ -157,7 +157,7 @@ class MenuDemoState extends State<MenuDemo> {
|
|||||||
title: new Text('An item with a simple menu'),
|
title: new Text('An item with a simple menu'),
|
||||||
subtitle: new Text(_simpleValue)
|
subtitle: new Text(_simpleValue)
|
||||||
),
|
),
|
||||||
items: <PopupMenuItem<String>>[
|
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
|
||||||
new PopupMenuItem<String>(
|
new PopupMenuItem<String>(
|
||||||
value: _simpleValue1,
|
value: _simpleValue1,
|
||||||
child: new Text(_simpleValue1)
|
child: new Text(_simpleValue1)
|
||||||
@ -178,7 +178,7 @@ class MenuDemoState extends State<MenuDemo> {
|
|||||||
title: new Text('An item with a checklist menu'),
|
title: new Text('An item with a checklist menu'),
|
||||||
trailing: new PopupMenuButton<String>(
|
trailing: new PopupMenuButton<String>(
|
||||||
onSelected: showCheckedMenuSelections,
|
onSelected: showCheckedMenuSelections,
|
||||||
items: <PopupMenuItem<String>>[
|
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
|
||||||
new CheckedPopupMenuItem<String>(
|
new CheckedPopupMenuItem<String>(
|
||||||
value: _checkedValue1,
|
value: _checkedValue1,
|
||||||
checked: isChecked(_checkedValue1),
|
checked: isChecked(_checkedValue1),
|
||||||
|
@ -53,7 +53,7 @@ class ScrollableTabsDemoState extends State<ScrollableTabsDemo> {
|
|||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
new PopupMenuButton<TabsDemoStyle>(
|
new PopupMenuButton<TabsDemoStyle>(
|
||||||
onSelected: changeDemoStyle,
|
onSelected: changeDemoStyle,
|
||||||
items: <PopupMenuItem<TabsDemoStyle>>[
|
itemBuilder: (BuildContext context) => <PopupMenuItem<TabsDemoStyle>>[
|
||||||
new PopupMenuItem<TabsDemoStyle>(
|
new PopupMenuItem<TabsDemoStyle>(
|
||||||
value: TabsDemoStyle.iconsAndText,
|
value: TabsDemoStyle.iconsAndText,
|
||||||
child: new Text('Icons and Text')
|
child: new Text('Icons and Text')
|
||||||
|
@ -220,7 +220,7 @@ class StockHomeState extends State<StockHome> {
|
|||||||
),
|
),
|
||||||
new PopupMenuButton<_StockMenuItem>(
|
new PopupMenuButton<_StockMenuItem>(
|
||||||
onSelected: (_StockMenuItem value) { _handleStockMenu(context, value); },
|
onSelected: (_StockMenuItem value) { _handleStockMenu(context, value); },
|
||||||
items: <PopupMenuItem<_StockMenuItem>>[
|
itemBuilder: (BuildContext context) => <PopupMenuItem<_StockMenuItem>>[
|
||||||
new CheckedPopupMenuItem<_StockMenuItem>(
|
new CheckedPopupMenuItem<_StockMenuItem>(
|
||||||
value: _StockMenuItem.autorefresh,
|
value: _StockMenuItem.autorefresh,
|
||||||
checked: _autorefresh,
|
checked: _autorefresh,
|
||||||
|
@ -380,6 +380,9 @@ Future<dynamic/*=T*/> showMenu/*<T>*/({
|
|||||||
/// its menu to be dismissed.
|
/// its menu to be dismissed.
|
||||||
typedef void PopupMenuItemSelected<T>(T value);
|
typedef void PopupMenuItemSelected<T>(T value);
|
||||||
|
|
||||||
|
/// Signature used by [PopupMenuButton] to lazily construct the items shown when the button is pressed.
|
||||||
|
typedef List<PopupMenuEntry<T>> PopupMenuItemBuilder<T>(BuildContext context);
|
||||||
|
|
||||||
/// Displays a menu when pressed and calls [onSelected] when the menu is dismissed
|
/// Displays a menu when pressed and calls [onSelected] when the menu is dismissed
|
||||||
/// because an item was selected. The value passed to [onSelected] is the value of
|
/// because an item was selected. The value passed to [onSelected] is the value of
|
||||||
/// the selected menu item. If child is null then a standard 'navigation/more_vert'
|
/// the selected menu item. If child is null then a standard 'navigation/more_vert'
|
||||||
@ -387,15 +390,18 @@ typedef void PopupMenuItemSelected<T>(T value);
|
|||||||
class PopupMenuButton<T> extends StatefulWidget {
|
class PopupMenuButton<T> extends StatefulWidget {
|
||||||
PopupMenuButton({
|
PopupMenuButton({
|
||||||
Key key,
|
Key key,
|
||||||
this.items,
|
this.itemBuilder,
|
||||||
this.initialValue,
|
this.initialValue,
|
||||||
this.onSelected,
|
this.onSelected,
|
||||||
this.tooltip: 'Show menu',
|
this.tooltip: 'Show menu',
|
||||||
this.elevation: 8,
|
this.elevation: 8,
|
||||||
this.child
|
this.child
|
||||||
}) : super(key: key);
|
}) : super(key: key) {
|
||||||
|
assert(itemBuilder != null);
|
||||||
|
}
|
||||||
|
|
||||||
final List<PopupMenuEntry<T>> items;
|
/// Called when the button is pressed to create the items to show in the menu.
|
||||||
|
final PopupMenuItemBuilder<T> itemBuilder;
|
||||||
|
|
||||||
final T initialValue;
|
final T initialValue;
|
||||||
|
|
||||||
@ -420,7 +426,7 @@ class _PopupMenuButtonState<T> extends State<PopupMenuButton<T>> {
|
|||||||
showMenu/*<T>*/(
|
showMenu/*<T>*/(
|
||||||
context: context,
|
context: context,
|
||||||
elevation: config.elevation,
|
elevation: config.elevation,
|
||||||
items: config.items,
|
items: config.itemBuilder(context),
|
||||||
initialValue: config.initialValue,
|
initialValue: config.initialValue,
|
||||||
position: new ModalPosition(
|
position: new ModalPosition(
|
||||||
left: topLeft.x,
|
left: topLeft.x,
|
||||||
|
Loading…
Reference in New Issue
Block a user