Flutter中如何基于DropdownMenu的onSelected更新TextField?
问题描述
我编写了一段Flutter代码,期望UI中“Result”文本旁的TextField能根据DropdownMenu的选项变化自动更新。但当前选择下拉菜单的新选项时,该TextField不会自动更新,仅当修改旁边的非只读TextField时才会变化。我尝试给firstController添加监听器,但并未生效。
代码如下:
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } const List<String> list = <String>[ "A", "B", "C", ]; class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { late final TextEditingController firstController; late final TextEditingController controllerResult; late String dropdownValue = list.first; @override void initState() { super.initState(); firstController = TextEditingController(); controllerResult = TextEditingController(); } @override void dispose() { firstController.dispose(); controllerResult.dispose(); super.dispose(); } @override Widget build(BuildContext context) { ComputeResult cr; return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title), ), body: Container( padding: const EdgeInsets.all(10.0), child: Column( children: [ Row( children: [ Expanded( flex: 5, child: TextField( controller: firstController, decoration: const InputDecoration( border: OutlineInputBorder(), hintText: 'Value', ), keyboardType: TextInputType.number, onChanged: (value) { if (firstController.text.isNotEmpty) { switch (dropdownValue) { case "A": controllerResult.text = "-1"; break; case "B": controllerResult.text = "-2"; break; case "C": cr = ComputeResult.named03( double.parse(firstController.text)); controllerResult.text = cr.value01.toString(); break; } } else { controllerResult.text = ""; } }, ), ), Expanded( flex: 5, child: DropdownMenu<String>( initialSelection: list.first, onSelected: (String? value) { setState(() { dropdownValue = value!; }); }, dropdownMenuEntries: list.map<DropdownMenuEntry<String>>((String value) { return DropdownMenuEntry<String>( value: value, label: value); }).toList(), ), ), ], ), SingleChildScrollView( child: Column( children: [ Row( children: [ Expanded( flex: 5, child: TextField( readOnly: true, controller: controllerResult, ), ), Expanded( flex: 5, child: Text("Result"), ), ], ), ], ), ), ], ), ), ); } } class ComputeResult { ComputeResult.named01(this.value01) { value02 = value01 + 100; value03 = value01 + 110; } ComputeResult.named02(this.value02) { value01 = value02 + 200; value03 = value02 + 210; } ComputeResult.named03(this.value03) { value01 = value03 + 300; value02 = value03 + 310; } double value01 = 0; double value02 = 0; double value03 = 0; }
解决方案
问题核心是:DropdownMenu的onSelected仅更新了dropdownValue的状态,但没有触发结果计算逻辑——结果计算只绑定在了输入框的onChanged事件上,所以切换下拉选项时不会更新结果。
修复步骤:
- 抽离计算逻辑为独立方法:把输入框
onChanged里的计算代码提取成_updateResult()方法,实现逻辑复用。 - 在Dropdown切换时调用计算方法:更新
dropdownValue状态后,立即调用_updateResult()刷新结果。 - 简化输入框的
onChanged:直接调用抽离后的计算方法即可。
修改后的完整代码:
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } const List<String> list = <String>[ "A", "B", "C", ]; class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { late final TextEditingController firstController; late final TextEditingController controllerResult; late String dropdownValue = list.first; @override void initState() { super.initState(); firstController = TextEditingController(); controllerResult = TextEditingController(); } @override void dispose() { firstController.dispose(); controllerResult.dispose(); super.dispose(); } // 抽离的结果计算方法 void _updateResult() { if (firstController.text.isNotEmpty) { switch (dropdownValue) { case "A": controllerResult.text = "-1"; break; case "B": controllerResult.text = "-2"; break; case "C": final cr = ComputeResult.named03(double.parse(firstController.text)); controllerResult.text = cr.value01.toString(); break; } } else { controllerResult.text = ""; } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title), ), body: Container( padding: const EdgeInsets.all(10.0), child: Column( children: [ Row( children: [ Expanded( flex: 5, child: TextField( controller: firstController, decoration: const InputDecoration( border: OutlineInputBorder(), hintText: 'Value', ), keyboardType: TextInputType.number, onChanged: (value) { _updateResult(); }, ), ), Expanded( flex: 5, child: DropdownMenu<String>( initialSelection: list.first, onSelected: (String? value) { setState(() { dropdownValue = value!; }); _updateResult(); // 切换下拉后立即计算结果 }, dropdownMenuEntries: list.map<DropdownMenuEntry<String>>((String value) { return DropdownMenuEntry<String>( value: value, label: value); }).toList(), ), ), ], ), SingleChildScrollView( child: Column( children: [ Row( children: [ Expanded( flex: 5, child: TextField( readOnly: true, controller: controllerResult, ), ), Expanded( flex: 5, child: Text("Result"), ), ], ), ], ), ), ], ), ), ); } } class ComputeResult { ComputeResult.named01(this.value01) { value02 = value01 + 100; value03 = value01 + 110; } ComputeResult.named02(this.value02) { value01 = value02 + 200; value03 = value02 + 210; } ComputeResult.named03(this.value03) { value01 = value03 + 300; value02 = value03 + 310; } double value01 = 0; double value02 = 0; double value03 = 0; }
这样修改后,无论是切换下拉选项还是修改输入框内容,都会触发结果计算并自动更新“Result”旁的TextField。
内容的提问来源于stack exchange,提问作者rusty
相关产品推荐
相关产品推荐

