Flutter如何获取自定义NumberSelector组件内部值并传值到新页面
解决Flutter组件状态值传递问题
方案一:状态提升(推荐)
把NumberSelector的状态(selectorValue)提升到父组件ExcersizeInput中,让父组件直接掌控数值,点击按钮时就能直接传递给下一个页面。
修改步骤:
- 将
ExcersizeInput改为StatefulWidget,在其State类中维护cyclesVal变量。 - 给
NumberSelector添加回调参数,内部数值变化时通知父组件更新。 - 让
startTimer直接使用父组件的cyclesVal。
修改后的代码:
ExcersizeInput组件
class ExcersizeInput extends StatefulWidget { const ExcersizeInput({super.key}); @override State<ExcersizeInput> createState() => _ExcersizeInputState(); } class _ExcersizeInputState extends State<ExcersizeInput> { int cyclesVal = 1; void startTimer(BuildContext context) { Navigator.push( context, MaterialPageRoute( builder: (context) => TimerPage( cycleCount: cyclesVal, ), )); } @override Widget build(BuildContext context) { return Column(children: [ Column( children: [ NumberSelector( title: "Cycles", initialValue: cyclesVal, onValueChanged: (newValue) { setState(() { cyclesVal = newValue; }); }, ), ], ), ElevatedButton.icon( onPressed: () => startTimer(context), label: const Text("Start"), icon: const Icon(Icons.start_outlined), ) ]); } }
NumberSelector组件
class NumberSelector extends StatefulWidget { final String title; final int initialValue; final Function(int) onValueChanged; // 添加回调函数 const NumberSelector({ super.key, required this.title, required this.initialValue, required this.onValueChanged, }); @override State<NumberSelector> createState() => _NumberSelectorState(); } class _NumberSelectorState extends State<NumberSelector> { late int selectorValue; @override void initState() { super.initState(); selectorValue = widget.initialValue; // 从父组件初始化数值 } void updateValue(bool ifAdd) { // 修正参数类型为bool setState(() { if (ifAdd) { if (selectorValue < 9999) { selectorValue++; } } else { if (selectorValue > 1) { selectorValue--; } } widget.onValueChanged(selectorValue); // 通知父组件数值更新 }); } @override Widget build(BuildContext context) { final ColorScheme colors = Theme.of(context).colorScheme; return Column( children: [ Text(widget.title, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold)), Row( children: [ IconButton( onPressed: () => updateValue(false), icon: const Icon(Icons.remove), // style: styleContainedButton, // 若未定义该变量可注释或补充 ), Text(selectorValue.toString(), style: const TextStyle(fontSize: 16)), IconButton( onPressed: () => updateValue(true), icon: const Icon(Icons.add), // style: styleContainedButton, ), ], ), ], ); } }
方案二:使用GlobalKey(不推荐,破坏封装)
通过GlobalKey直接获取NumberSelector的State实例,读取内部的selectorValue。
修改步骤:
- 在
ExcersizeInput的State类中定义GlobalKey。 - 给
NumberSelector绑定该Key。 - 在
startTimer中通过Key获取State并读取数值。
修改后的代码:
ExcersizeInput组件
class ExcersizeInput extends StatefulWidget { const ExcersizeInput({super.key}); @override State<ExcersizeInput> createState() => _ExcersizeInputState(); } class _ExcersizeInputState extends State<ExcersizeInput> { final GlobalKey<_NumberSelectorState> _selectorKey = GlobalKey(); void startTimer(BuildContext context) { int cyclesVal = _selectorKey.currentState!.selectorValue; Navigator.push( context, MaterialPageRoute( builder: (context) => TimerPage( cycleCount: cyclesVal, ), )); } @override Widget build(BuildContext context) { return Column(children: [ Column( children: [ NumberSelector( key: _selectorKey, title: "Cycles", ), ], ), ElevatedButton.icon( onPressed: () => startTimer(context), label: const Text("Start"), icon: const Icon(Icons.start_outlined), ) ]); } }
NumberSelector组件
需要将内部变量改为公开:
class _NumberSelectorState extends State<NumberSelector> { int selectorValue = 1; // 去掉下划线,改为公开变量 // 其余代码不变 }
注意事项
- 状态提升是Flutter官方推荐的方式,符合组件设计原则,耦合度低,便于维护。
- GlobalKey方式虽简单,但会让父组件直接依赖子组件内部状态,破坏封装性,复杂项目中不建议使用。
内容的提问来源于stack exchange,提问作者Adam Smielewski
相关产品推荐
相关产品推荐

