Flutter:如何通过PopupMenuButton预填充表单数据
核心思路和你之前用InkWell的逻辑一致:只要拿到当前操作的账号实例/ID,就能复用原来的跳转和预填充逻辑。下面分两种场景给出具体实现:
场景1:PopupMenuButton在AccountView组件内部
因为你通过ChangeNotifierProvider.value把accounts[index]传入了AccountView,所以在AccountView里可以直接获取当前账号实例:
// 在AccountView组件中 Widget build(BuildContext context) { // 获取当前账号实例 final currentAccount = Provider.of<Account>(context); return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // 原有账号信息展示部分 ..., // 弹出菜单按钮 PopupMenuButton<AccountOptions>( onSelected: (selection) { if (selection == AccountOptions.editAccount) { // 和InkWell一样传ID跳转 Navigator.of(context).pushNamed( EditSettings.routeName, arguments: currentAccount.id ); } else if (selection == AccountOptions.passVisible) { setState(() => _passwordVisible = true); } else if (selection == AccountOptions.passInvisible) { setState(() => _passwordVisible = false); } }, itemBuilder: (context) => [ const PopupMenuItem( value: AccountOptions.passVisible, child: Text('显示密码'), ), const PopupMenuItem( value: AccountOptions.passInvisible, child: Text('隐藏密码'), ), const PopupMenuItem( value: AccountOptions.editAccount, child: Text('编辑账号'), ), ], ) ], ); }
场景2:PopupMenuButton在ListView的itemBuilder层级
如果弹出菜单和InkWell同级别,直接在构建时缓存当前账号即可:
itemBuilder: ((context, index) { // 缓存当前索引对应的账号 final currentAccount = accounts[index]; return Container( child: Row( children: [ InkWell( onTap: () => Navigator.of(context) .pushNamed(EditSettings.routeName, arguments: currentAccount.id), child: ChangeNotifierProvider.value( value: currentAccount, // 注意:key要用单个账号的唯一标识,比如ID,不是整个accounts列表 key: ValueKey(currentAccount.id), child: const AccountView(), ), ), PopupMenuButton<AccountOptions>( onSelected: (selection) { setState(() { if (selection == AccountOptions.editAccount) { // 直接用缓存的账号ID跳转 Navigator.of(context).pushNamed( EditSettings.routeName, arguments: currentAccount.id ); } else if (selection == AccountOptions.passVisible) { _passwordVisible = true; } else if (selection == AccountOptions.passInvisible) { _passwordVisible = false; } }); }, itemBuilder: (context) => [ const PopupMenuItem(value: AccountOptions.passVisible, child: Text('显示密码')), const PopupMenuItem(value: AccountOptions.passInvisible, child: Text('隐藏密码')), const PopupMenuItem(value: AccountOptions.editAccount, child: Text('编辑账号')), ], ) ], ), ); })
预填充表单的复用逻辑
跳转后的EditSettings页面不需要修改,依然用原来的方式获取ID并匹配账号数据:
class EditSettings extends StatelessWidget { static const routeName = '/edit-settings'; @override Widget build(BuildContext context) { final accountId = ModalRoute.of(context)!.settings.arguments as String; // 从Provider或账号列表中找到对应数据 final targetAccount = Provider.of<AccountProvider>(context).findById(accountId); // 用账号数据初始化表单控制器 final nameCtrl = TextEditingController(text: targetAccount.name); final urlCtrl = TextEditingController(text: targetAccount.url); final usernameCtrl = TextEditingController(text: targetAccount.username); final passwordCtrl = TextEditingController(text: targetAccount.password); return Scaffold( appBar: AppBar(title: const Text('编辑账号')), body: Form( child: Column( children: [ TextFormField(controller: nameCtrl, decoration: const InputDecoration(labelText: '名称')), TextFormField(controller: urlCtrl, decoration: const InputDecoration(labelText: '网址')), TextFormField(controller: usernameCtrl, decoration: const InputDecoration(labelText: '用户名')), TextFormField(controller: passwordCtrl, decoration: const InputDecoration(labelText: '密码')), ElevatedButton(onPressed: () {/* 保存逻辑 */}, child: const Text('保存')) ], ), ), ); } }
内容的提问来源于stack exchange,提问作者Deucal
相关产品推荐
相关产品推荐

