Flutter:如何从Tab向DefaultTabController传递变量
问题描述
我在Scaffold中嵌套了一个包含两个页面的DefaultTabController,Scaffold的AppBar内设有一个保存按钮,希望该按钮能基于其中一个Tab中计算得到的变量,向前一页面返回对应值。具体而言,变量gewicht在第一个Tab页面GewichtsrechnerEinfach中完成计算与更新,请问如何将该变量传递到主页面,供保存按钮使用?
相关代码
DefaultTabController代码
DefaultTabController( initialIndex: index, length: 2, child: Scaffold( backgroundColor: Theme.of(context).scaffoldBackgroundColor, appBar: AppBar( elevation: 0, backgroundColor: fumigruen_accent, leading: CloseButton( color: Colors.black, onPressed: () { Navigator.of(context).pop(); }, ), actions: buildEditingActions(), ), body: Column(children: [ tabBar(), Expanded( child: TabBarView(children: [ //1st Tab GewichtsrechnerEinfach(), //2nd Tab Column() ]), ) ]), ));}
保存按钮代码
List<Widget> buildEditingActions() => [ ElevatedButton.icon( style: ElevatedButton.styleFrom( backgroundColor: fumigruen_accent, elevation: 0, foregroundColor: Colors.black, ), onPressed: () { Navigator.of(context).pop(gewicht); }, icon: Icon(Icons.save), label: Text("Speichern")) ];
TabBar代码
Widget tabBar() => TabBar( labelColor: Theme.of(context).primaryColor, indicatorColor: Theme.of(context).primaryColor, labelStyle: TextStyle(fontWeight: FontWeight.bold), tabs: [ Tab( child: Row(mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.assessment_outlined, ), SizedBox( width: 5, ), Text("Einfach") ]), ), Tab( child: Row(mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.addchart, ), SizedBox( width: 5, ), Text("Fortgeschritten") ]), ), ]);
GewichtsrechnerEinfach部分代码
class _GewichtsrechnerEinfachState extends State<GewichtsrechnerEinfach> { final _formKey = GlobalKey<FormState>(); num koerperlaenge = 0; num brustumfang = 0; var _koerperlaengeControler = TextEditingController(); var _brustumfangControler = TextEditingController(); num gewicht = 0; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(8.0), child: SingleChildScrollView( child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ //{two textinput fields setting the variables koerperlaenge and brustumfang are here} Center( child: Container( width: MediaQuery.of(context).size.width * 0.8, decoration: ThemeHelper().buttonBoxDecoration(context), child: ElevatedButton( style: ThemeHelper().buttonStyle(), child: Padding( padding: EdgeInsets.fromLTRB(10, 0, 10, 0), child: Text( "berechnen".toUpperCase(), style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), onPressed: () async { if (_formKey.currentState!.validate()) { setState(() { gewicht = Gewichtskalkulator().einfach( brustumfang.toDouble(), koerperlaenge.toDouble()); }); } }), ), ), ], ), ), ), ); }
解决方案
下面提供两种实用的实现方式,适配不同场景需求:
方法一:通过GlobalKey直接获取子组件状态
这是最直接的实现方式,通过GlobalKey可以直接访问子Widget状态类中的变量:
1. 主页面修改
定义GlobalKey并传递给子组件:
// 定义GlobalKey,指定子组件状态类型 final _einfachTabKey = GlobalKey<_GewichtsrechnerEinfachState>(); DefaultTabController( initialIndex: index, length: 2, child: Scaffold( // ... 其余代码不变 body: Column(children: [ tabBar(), Expanded( child: TabBarView(children: [ // 将GlobalKey传递给子组件 GewichtsrechnerEinfach(key: _einfachTabKey), Column() ]), ) ]), ));
2. 保存按钮修改
通过GlobalKey获取子组件的gewicht值:
List<Widget> buildEditingActions() => [ ElevatedButton.icon( // ... 样式代码不变 onPressed: () { // 获取子组件的gewicht,默认值设为0防止空指针 final gewicht = _einfachTabKey.currentState?.gewicht ?? 0; Navigator.of(context).pop(gewicht); }, icon: Icon(Icons.save), label: Text("Speichern")) ];
3. 子组件注意事项
如果主页面和子组件不在同一个文件中,需要将子组件的State类改为公开(去掉类名前的下划线):
// 修改State类为公开 class GewichtsrechnerEinfachState extends State<GewichtsrechnerEinfach> { // ... 其余代码不变 } // 对应的Widget类 class GewichtsrechnerEinfach extends StatefulWidget { const GewichtsrechnerEinfach({super.key}); // 接收Key参数 @override GewichtsrechnerEinfachState createState() => GewichtsrechnerEinfachState(); }
方法二:通过回调函数传递值
这种方式符合Flutter状态向上传递的设计原则,子组件通过回调将计算结果通知父组件:
1. 子组件修改
添加回调函数参数,计算完成后触发回调:
class GewichtsrechnerEinfach extends StatefulWidget { // 定义回调函数,用于传递计算后的gewicht final Function(num) onGewichtCalculated; const GewichtsrechnerEinfach({super.key, required this.onGewichtCalculated}); @override _GewichtsrechnerEinfachState createState() => _GewichtsrechnerEinfachState(); } class _GewichtsrechnerEinfachState extends State<GewichtsrechnerEinfach> { // ... 其余变量定义不变 @override Widget build(BuildContext context) { return Padding( // ... 其余代码不变 child: ElevatedButton( // ... 样式代码不变 onPressed: () async { if (_formKey.currentState!.validate()) { setState(() { gewicht = Gewichtskalkulator().einfach( brustumfang.toDouble(), koerperlaenge.toDouble()); // 触发回调,传递计算结果 widget.onGewichtCalculated(gewicht); }); } }), ); } }
2. 主页面修改
定义变量接收回调值,并传递回调函数给子组件:
// 主页面定义变量保存gewicht num _gewicht = 0; DefaultTabController( initialIndex: index, length: 2, child: Scaffold( // ... 其余代码不变 body: Column(children: [ tabBar(), Expanded( child: TabBarView(children: [ GewichtsrechnerEinfach( onGewichtCalculated: (value) { // 更新主页面的gewicht变量 setState(() { _gewicht = value; }); }, ), Column() ]), ) ]), ));
3. 保存按钮修改
直接使用主页面的_gewicht变量:
List<Widget> buildEditingActions() => [ ElevatedButton.icon( // ... 样式代码不变 onPressed: () { Navigator.of(context).pop(_gewicht); }, icon: Icon(Icons.save), label: Text("Speichern")) ];
内容的提问来源于stack exchange,提问作者Matthias Felder
相关产品推荐
相关产品推荐

