如何打开 PopupMenuButton?
How to open a PopupMenuButton?
如何从第二个小部件打开弹出菜单?
final button = new PopupMenuButton(
itemBuilder: (_) => <PopupMenuItem<String>>[
new PopupMenuItem<String>(
child: const Text('Doge'), value: 'Doge'),
new PopupMenuItem<String>(
child: const Text('Lion'), value: 'Lion'),
],
onSelected: _doSomething);
final tile = new ListTile(title: new Text('Doge or lion?'), trailing: button);
我想通过点击 tile
打开 button
的菜单。
我认为没有办法实现这种行为。尽管您可以将 onTap
属性附加到图块,但您无法从 'outside'
访问 MenuButton
您可以采用的一种方法是使用 ExpansionPanels,因为它们看起来像 ListTiles,旨在允许轻松修改和编辑。
我找到了您问题的解决方案。您可以为 PopupMenuButton 提供一个子项,它可以是任何包含 ListTile 的 Widget(请参见下面的代码)。唯一的问题是 PopupMenu 在 ListTile 的左侧打开。
final popupMenu = new PopupMenuButton(
child: new ListTile(
title: new Text('Doge or lion?'),
trailing: const Icon(Icons.more_vert),
),
itemBuilder: (_) => <PopupMenuItem<String>>[
new PopupMenuItem<String>(
child: new Text('Doge'), value: 'Doge'),
new PopupMenuItem<String>(
child: new Text('Lion'), value: 'Lion'),
],
onSelected: _doSomething,
)
这可行,但不够优雅(并且与上面 Rainer 的解决方案有相同的显示问题:
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey _menuKey = GlobalKey();
@override
Widget build(BuildContext context) {
final button = PopupMenuButton(
key: _menuKey,
itemBuilder: (_) => const<PopupMenuItem<String>>[
PopupMenuItem<String>(
child: Text('Doge'), value: 'Doge'),
PopupMenuItem<String>(
child: Text('Lion'), value: 'Lion'),
],
onSelected: (_) {});
final tile =
ListTile(title: Text('Doge or lion?'), trailing: button, onTap: () {
// This is a hack because _PopupMenuButtonState is private.
dynamic state = _menuKey.currentState;
state.showButtonMenu();
});
return Scaffold(
body: Center(
child: tile,
),
);
}
}
我怀疑您实际要求的是 https://github.com/flutter/flutter/issues/254 or https://github.com/flutter/flutter/issues/8277 跟踪的内容——将标签与控件相关联并使标签可点击的能力——这是一个缺失的功能来自 Flutter 框架。
我认为这样会更好,而不是显示 PopupMenuButton
void _showPopupMenu() async {
await showMenu(
context: context,
position: RelativeRect.fromLTRB(100, 100, 100, 100),
items: [
PopupMenuItem<String>(
child: const Text('Doge'), value: 'Doge'),
PopupMenuItem<String>(
child: const Text('Lion'), value: 'Lion'),
],
elevation: 8.0,
);
}
有时您会想要在您按下按钮的位置显示_showPopupMenu
为此使用 GestureDetector
final tile = new ListTile(
title: new Text('Doge or lion?'),
trailing: GestureDetector(
onTapDown: (TapDownDetails details) {
_showPopupMenu(details.globalPosition);
},
child: Container(child: Text("Press Me")),
),
);
然后 _showPopupMenu 会像
_showPopupMenu(Offset offset) async {
double left = offset.dx;
double top = offset.dy;
await showMenu(
context: context,
position: RelativeRect.fromLTRB(left, top, 0, 0),
items: [
...,
elevation: 8.0,
);
}
使用 popup_menu 包作为库
在您的 pubspec.yaml
依赖项中添加 popup_menu: ^1.0.5
。并导入它:
import 'package:popup_menu/popup_menu.dart';
首先,您应该在代码中的某处设置上下文。如下所示:
PopupMenu.context = context;
然后创建一个 showPopup
小部件并传递所需的参数:
void showPopup(Offset offset) {
PopupMenu menu = PopupMenu(
// backgroundColor: Colors.teal,
// lineColor: Colors.tealAccent,
maxColumn: 3,
items: [
MenuItem(title: 'Copy', image: Image.asset('assets/copy.png')),
MenuItem(title: 'Mail', image: Icon(Icons.mail, color: Colors.white)),
MenuItem(title: 'Power',image: Icon(Icons.power, color: Colors.white,)),
],
onClickMenu: onClickMenu,
stateChanged: stateChanged,
onDismiss: onDismiss);
menu.show(rect: Rect.fromPoints(offset, offset));
}
void stateChanged(bool isShow) {
print('menu is ${isShow ? 'showing' : 'closed'}');
}
void onClickMenu(MenuItemProvider item) {
print('Click menu -> ${item.menuTitle}');
}
void onDismiss() {
print('Menu is dismiss');
}
这是打开的弹窗
@override
Widget build(BuildContext context) {
PopupMenu.context = context; // This is the set context
return Scaffold(
appBar: AppBar(
title: Text('Show Popup')),
body: Stack(
children: <Widget>[
ListView.builder(
itemCount: list.length,
itemBuilder: (context, index) {
return MaterialButton(
child: GestureDetector(
onTapUp: (TapUpDetails details) {
showPopup(details.globalPosition);
},
child: ListTile(
leading: IconButton(
icon: Icon(Icons.restaurant_menu),
),
title: Text("Select your categories"),
subtitle: Text("Sub Title"),
// onTap: showPopup,
),
),
);
},
),
],
),
);
}
截图:
完整代码:
class MyPage extends StatelessWidget {
final GlobalKey<PopupMenuButtonState<int>> _key = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
PopupMenuButton<int>(
key: _key,
itemBuilder: (context) {
return <PopupMenuEntry<int>>[
PopupMenuItem(child: Text('0'), value: 0),
PopupMenuItem(child: Text('1'), value: 1),
];
},
),
],
),
body: RaisedButton(
onPressed: () => _key.currentState.showButtonMenu(),
child: Text('Open/Close menu'),
),
);
}
}
如何从第二个小部件打开弹出菜单?
final button = new PopupMenuButton(
itemBuilder: (_) => <PopupMenuItem<String>>[
new PopupMenuItem<String>(
child: const Text('Doge'), value: 'Doge'),
new PopupMenuItem<String>(
child: const Text('Lion'), value: 'Lion'),
],
onSelected: _doSomething);
final tile = new ListTile(title: new Text('Doge or lion?'), trailing: button);
我想通过点击 tile
打开 button
的菜单。
我认为没有办法实现这种行为。尽管您可以将 onTap
属性附加到图块,但您无法从 'outside'
您可以采用的一种方法是使用 ExpansionPanels,因为它们看起来像 ListTiles,旨在允许轻松修改和编辑。
我找到了您问题的解决方案。您可以为 PopupMenuButton 提供一个子项,它可以是任何包含 ListTile 的 Widget(请参见下面的代码)。唯一的问题是 PopupMenu 在 ListTile 的左侧打开。
final popupMenu = new PopupMenuButton(
child: new ListTile(
title: new Text('Doge or lion?'),
trailing: const Icon(Icons.more_vert),
),
itemBuilder: (_) => <PopupMenuItem<String>>[
new PopupMenuItem<String>(
child: new Text('Doge'), value: 'Doge'),
new PopupMenuItem<String>(
child: new Text('Lion'), value: 'Lion'),
],
onSelected: _doSomething,
)
这可行,但不够优雅(并且与上面 Rainer 的解决方案有相同的显示问题:
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey _menuKey = GlobalKey();
@override
Widget build(BuildContext context) {
final button = PopupMenuButton(
key: _menuKey,
itemBuilder: (_) => const<PopupMenuItem<String>>[
PopupMenuItem<String>(
child: Text('Doge'), value: 'Doge'),
PopupMenuItem<String>(
child: Text('Lion'), value: 'Lion'),
],
onSelected: (_) {});
final tile =
ListTile(title: Text('Doge or lion?'), trailing: button, onTap: () {
// This is a hack because _PopupMenuButtonState is private.
dynamic state = _menuKey.currentState;
state.showButtonMenu();
});
return Scaffold(
body: Center(
child: tile,
),
);
}
}
我怀疑您实际要求的是 https://github.com/flutter/flutter/issues/254 or https://github.com/flutter/flutter/issues/8277 跟踪的内容——将标签与控件相关联并使标签可点击的能力——这是一个缺失的功能来自 Flutter 框架。
我认为这样会更好,而不是显示 PopupMenuButton
void _showPopupMenu() async {
await showMenu(
context: context,
position: RelativeRect.fromLTRB(100, 100, 100, 100),
items: [
PopupMenuItem<String>(
child: const Text('Doge'), value: 'Doge'),
PopupMenuItem<String>(
child: const Text('Lion'), value: 'Lion'),
],
elevation: 8.0,
);
}
有时您会想要在您按下按钮的位置显示_showPopupMenu 为此使用 GestureDetector
final tile = new ListTile(
title: new Text('Doge or lion?'),
trailing: GestureDetector(
onTapDown: (TapDownDetails details) {
_showPopupMenu(details.globalPosition);
},
child: Container(child: Text("Press Me")),
),
);
然后 _showPopupMenu 会像
_showPopupMenu(Offset offset) async {
double left = offset.dx;
double top = offset.dy;
await showMenu(
context: context,
position: RelativeRect.fromLTRB(left, top, 0, 0),
items: [
...,
elevation: 8.0,
);
}
使用 popup_menu 包作为库
在您的 pubspec.yaml
依赖项中添加 popup_menu: ^1.0.5
。并导入它:
import 'package:popup_menu/popup_menu.dart';
首先,您应该在代码中的某处设置上下文。如下所示:
PopupMenu.context = context;
然后创建一个 showPopup
小部件并传递所需的参数:
void showPopup(Offset offset) {
PopupMenu menu = PopupMenu(
// backgroundColor: Colors.teal,
// lineColor: Colors.tealAccent,
maxColumn: 3,
items: [
MenuItem(title: 'Copy', image: Image.asset('assets/copy.png')),
MenuItem(title: 'Mail', image: Icon(Icons.mail, color: Colors.white)),
MenuItem(title: 'Power',image: Icon(Icons.power, color: Colors.white,)),
],
onClickMenu: onClickMenu,
stateChanged: stateChanged,
onDismiss: onDismiss);
menu.show(rect: Rect.fromPoints(offset, offset));
}
void stateChanged(bool isShow) {
print('menu is ${isShow ? 'showing' : 'closed'}');
}
void onClickMenu(MenuItemProvider item) {
print('Click menu -> ${item.menuTitle}');
}
void onDismiss() {
print('Menu is dismiss');
}
这是打开的弹窗
@override
Widget build(BuildContext context) {
PopupMenu.context = context; // This is the set context
return Scaffold(
appBar: AppBar(
title: Text('Show Popup')),
body: Stack(
children: <Widget>[
ListView.builder(
itemCount: list.length,
itemBuilder: (context, index) {
return MaterialButton(
child: GestureDetector(
onTapUp: (TapUpDetails details) {
showPopup(details.globalPosition);
},
child: ListTile(
leading: IconButton(
icon: Icon(Icons.restaurant_menu),
),
title: Text("Select your categories"),
subtitle: Text("Sub Title"),
// onTap: showPopup,
),
),
);
},
),
],
),
);
}
截图:
完整代码:
class MyPage extends StatelessWidget {
final GlobalKey<PopupMenuButtonState<int>> _key = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
PopupMenuButton<int>(
key: _key,
itemBuilder: (context) {
return <PopupMenuEntry<int>>[
PopupMenuItem(child: Text('0'), value: 0),
PopupMenuItem(child: Text('1'), value: 1),
];
},
),
],
),
body: RaisedButton(
onPressed: () => _key.currentState.showButtonMenu(),
child: Text('Open/Close menu'),
),
);
}
}