如何结合TextEditingController与StateNotifierProvider处理Double类型价格输入
Flutter处理价格输入并适配StateNotifierProvider的解决方案
核心问题梳理
你的代码里存在几个关键问题导致价格输入无法正常工作:
- 输入框未绑定控制器:创建了
_nameController和_priceController,但对应的TextFormField没设置controller属性,输入内容根本没被捕获 - 可空值传递错误:
addFood要求传入非空double,但priceName是可空类型,解析失败时会是null,直接传递会触发类型错误 - 保存按钮未关联逻辑:Save按钮的
onPressed是空实现,点击不会触发保存操作 - 缺少表单验证:没利用Form的验证机制提前拦截无效输入
修复后的FoodScreen代码
import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:kitchen/Provider/fav_food.dart'; class FoodScreen extends ConsumerStatefulWidget { const FoodScreen({Key? key}) : super(key: key); @override ConsumerState<FoodScreen> createState() => _FoodScreen(); } class _FoodScreen extends ConsumerState<FoodScreen> { final _keyState = GlobalKey<FormState>(); final _nameController = TextEditingController(); final _priceController = TextEditingController(); void _save() { if (!_keyState.currentState!.validate()) return; final enteredName = _nameController.text.trim(); final parsedPrice = double.tryParse(_priceController.text.trim()); if (parsedPrice == null) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('请输入有效的价格数字')), ); return; } ref.read(userPlaceProvider.notifier).addFood(enteredName, parsedPrice); Navigator.of(context).pop(); // 保存后返回上一页,可根据需求调整 } @override void dispose() { _nameController.dispose(); _priceController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.green, title: const Text('Food Screen'), ), body: Form( key: _keyState, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ TextFormField( controller: _nameController, maxLength: 40, decoration: const InputDecoration( border: UnderlineInputBorder(), labelText: 'Food name', ), validator: (value) { if (value == null || value.trim().isEmpty) { return '请输入食物名称'; } return null; }, ), const SizedBox(height: 16), TextFormField( controller: _priceController, keyboardType: TextInputType.numberWithOptions(decimal: true), maxLength: 10, decoration: const InputDecoration( border: UnderlineInputBorder(), labelText: 'Food price', ), validator: (value) { if (value == null || value.trim().isEmpty) { return '请输入价格'; } if (double.tryParse(value.trim()) == null) { return '请输入有效的数字'; } return null; }, ), const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ ElevatedButton( onPressed: () => Navigator.of(context).pop(), style: ElevatedButton.styleFrom( backgroundColor: Colors.green, foregroundColor: Colors.white, ), child: const Text('Cancel'), ), const SizedBox(width: 16), ElevatedButton( onPressed: _save, style: ElevatedButton.styleFrom( backgroundColor: Colors.green, foregroundColor: Colors.white, ), child: const Text('Save'), ), ], ), ], ), ), ), ); } }
关键修改说明
- 绑定控制器到输入框:给食物名称和价格的
TextFormField分别设置controller: _nameController和controller: _priceController,确保输入内容能被捕获 - 添加表单验证:给每个输入框添加
validator回调,提前检查输入是否为空、价格是否为有效数字,点击保存时先通过_keyState.currentState!.validate()验证表单 - 优化价格处理逻辑:解析前先trim输入内容,避免空格导致解析失败;解析失败时通过SnackBar提示用户,不再传递空值给
addFood - 绑定保存方法到按钮:把Save按钮的
onPressed设为_save,点击时触发保存逻辑 - 释放控制器资源:重写
dispose方法,销毁控制器避免内存泄漏 - 优化键盘类型:价格输入框设置
keyboardType: TextInputType.numberWithOptions(decimal: true),弹出数字键盘提升用户体验
保持原Provider代码不变
你的Provider代码无需修改,addFood方法的非空double参数要求是合理的,只要确保传递的价格是有效非空值即可。
内容的提问来源于stack exchange,提问作者Allan
相关产品推荐
相关产品推荐

