You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合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'),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

关键修改说明

  1. 绑定控制器到输入框:给食物名称和价格的TextFormField分别设置controller: _nameController和controller: _priceController,确保输入内容能被捕获
  2. 添加表单验证:给每个输入框添加validator回调,提前检查输入是否为空、价格是否为有效数字,点击保存时先通过_keyState.currentState!.validate()验证表单
  3. 优化价格处理逻辑:解析前先trim输入内容,避免空格导致解析失败;解析失败时通过SnackBar提示用户,不再传递空值给addFood
  4. 绑定保存方法到按钮:把Save按钮的onPressed设为_save,点击时触发保存逻辑
  5. 释放控制器资源:重写dispose方法,销毁控制器避免内存泄漏
  6. 优化键盘类型:价格输入框设置keyboardType: TextInputType.numberWithOptions(decimal: true),弹出数字键盘提升用户体验

保持原Provider代码不变

你的Provider代码无需修改,addFood方法的非空double参数要求是合理的,只要确保传递的价格是有效非空值即可。

内容的提问来源于stack exchange,提问作者Allan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 09:40:58