Flutter实现SI单位双向转换及TextField输入处理技术问询
解决Flutter单位转换应用的双向转换与条件判断问题
Hey Lakshan, 我来帮你搞定这个单位转换应用的问题!咱们一步步来实现你要的双向转换功能,同时把Flutter里的条件判断用法也讲明白。
首先,我先梳理下你的需求:两个输入框对应不同单位,输入其中一个时自动转换到另一个;支持双向同步;还要学会Flutter里的条件判断逻辑。接下来咱们逐个解决这些问题。
一、先调整基础结构:添加双输入控制器
你现在只有一个控制器,我们需要给两个输入框各配一个控制器,这样才能分别监听和修改它们的内容。另外,要注意Dropdown里的单位值大小写要统一(比如你之前的"Kilogram"和"kilogram"会导致匹配错误),我已经帮你统一成小写了。
二、编写单位转换函数(核心:条件判断的用法)
这里我们用if-else或者switch-case来处理不同单位之间的转换逻辑,这就是Flutter里常用的条件判断方式。比如千克和克的转换,我们可以这样写:
double convertUnit(double input, String fromUnit, String toUnit) { if (fromUnit == toUnit) return input; // 相同单位直接返回原值 // 千克与克之间的转换 if (fromUnit == "kilogram" && toUnit == "gram") { return input * 1000; } else if (fromUnit == "gram" && toUnit == "kilogram") { return input / 1000; } // 以后可以在这里添加更多单位的转换逻辑,比如磅、盎司等 return input; }
如果单位类型多,也可以用switch-case来让代码更清晰:
double convertUnit(double input, String fromUnit, String toUnit) { if (fromUnit == toUnit) return input; switch('$fromUnit-$toUnit') { case 'kilogram-gram': return input * 1000; case 'gram-kilogram': return input / 1000; // 其他单位组合的case default: return input; } }
三、实现双向输入同步
我们需要给两个控制器添加监听事件,当其中一个输入框的内容变化时,自动计算并更新另一个输入框的内容。还要加个标记避免循环触发(比如A更新B,B又触发更新A)。
四、完整修改后的代码
下面是整合了所有功能的完整代码,每部分都加了注释:
class Weight extends StatefulWidget { @override _WeightState createState() => _WeightState(); } class _WeightState extends State<Weight> { String? _value1; // 第一个单位(比如kilogram) String? _value2; // 第二个单位(比如gram) final TextEditingController _controller1 = TextEditingController(); // 第一个输入框控制器 final TextEditingController _controller2 = TextEditingController(); // 第二个输入框控制器 bool _isUpdating = false; // 避免循环更新的标记 @override void initState() { super.initState(); // 监听第一个输入框的变化 _controller1.addListener(_onInput1Changed); // 监听第二个输入框的变化 _controller2.addListener(_onInput2Changed); } @override void dispose() { // 记得销毁控制器,避免内存泄漏 _controller1.dispose(); _controller2.dispose(); super.dispose(); } // 处理第一个输入框的变化,转换后更新第二个输入框 void _onInput1Changed() { if (_isUpdating || _value1 == null || _value2 == null) return; final input = double.tryParse(_controller1.text); if (input == null) { _controller2.clear(); return; } final result = convertUnit(input, _value1!, _value2!); _isUpdating = true; _controller2.text = result.toStringAsFixed(2); // 保留两位小数 _isUpdating = false; } // 处理第二个输入框的变化,转换后更新第一个输入框 void _onInput2Changed() { if (_isUpdating || _value1 == null || _value2 == null) return; final input = double.tryParse(_controller2.text); if (input == null) { _controller1.clear(); return; } final result = convertUnit(input, _value2!, _value1!); _isUpdating = true; _controller1.text = result.toStringAsFixed(2); _isUpdating = false; } // 单位转换核心函数,包含条件判断 double convertUnit(double input, String fromUnit, String toUnit) { if (fromUnit == toUnit) return input; // 千克和克的转换逻辑 if (fromUnit == "kilogram" && toUnit == "gram") { return input * 1000; } else if (fromUnit == "gram" && toUnit == "kilogram") { return input / 1000; } // 后续可以添加更多单位,比如: // if (fromUnit == "kilogram" && toUnit == "pound") { // return input * 2.20462; // } return input; } @override Widget build(BuildContext context) { return Material( child: Center( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 第一个单位选择器 DropdownButton<String>( items: const [ DropdownMenuItem(child: Text("Kilogram"), value: "kilogram"), DropdownMenuItem(child: Text("Gram"), value: "gram"), ], onChanged: (String? value) { setState(() { _value1 = value; // 单位切换后,重新触发转换 _onInput1Changed(); }); }, hint: const Text('Select Unit'), value: _value1, isExpanded: true, // 让下拉框占满宽度 ), const SizedBox(height: 10), // 第一个输入框 TextField( controller: _controller1, keyboardType: TextInputType.numberWithOptions(decimal: true), decoration: InputDecoration( border: const OutlineInputBorder(), labelText: _value1 != null ? "Enter amount in $_value1" : "Enter amount", ), ), const SizedBox(height: 50), // 第二个单位选择器 DropdownButton<String>( items: const [ DropdownMenuItem(child: Text("Kilogram"), value: "kilogram"), DropdownMenuItem(child: Text("Gram"), value: "gram"), ], onChanged: (String? value) { setState(() { _value2 = value; // 单位切换后,重新触发转换 _onInput2Changed(); }); }, hint: const Text('Select Unit'), value: _value2, isExpanded: true, ), const SizedBox(height: 10), // 第二个输入框 TextField( controller: _controller2, keyboardType: TextInputType.numberWithOptions(decimal: true), decoration: InputDecoration( border: const OutlineInputBorder(), labelText: _value2 != null ? "Enter amount in $_value2" : "Enter amount", ), ), const SizedBox(height: 50), // 转换按钮(其实现在已经自动转换了,按钮可以保留用来手动触发或者扩展功能) ElevatedButton( onPressed: () { // 手动触发转换的话,可以调用_onInput1Changed()或者_onInput2Changed() _onInput1Changed(); }, style: ElevatedButton.styleFrom( padding: const EdgeInsets.all(12), elevation: 15, ), child: const Text( "Convert", style: TextStyle(fontSize: 25, color: Colors.black), ), ), ], ), ), ), ); } }
关于Flutter中的条件判断补充
除了在逻辑代码里用if-else和switch-case,你还可以在Widget构建时用条件判断来动态渲染UI,比如:
// 示例:如果选中了单位,显示输入框,否则提示选择单位 Widget build(BuildContext context) { return Column( children: [ if (_value1 != null) TextField(...) else const Text("Please select a unit first!"), ], ); }
这样你的应用就完全实现了双向单位转换,同时也学会了Flutter里条件判断的多种用法啦!
内容的提问来源于stack exchange,提问作者Lakshan Costa
相关产品推荐
相关产品推荐

