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

Flutter中double.parse()报FormatException: Invalid double错误求助

问题排查:FormatException: Invalid double 解决方法

问题根源

  1. 字符串格式不兼容:salePriceController.text存储的是带美元符号$和千位分隔符,的货币字符串(如$4,249,000.00),double.parse()只能解析纯数字格式的字符串,无法识别这些非数字符号,直接解析会抛出FormatException。
  2. 格式化方法逻辑错误:你的_formatCurrency方法存在严重逻辑问题——不管输入的数值是什么,最终都返回"\$0.00",完全没有使用currencyFormatter.format(value)生成的正确格式化字符串,导致初始显示的售价永远为$0.00,和传入的salePrice不符。

修复方案

1. 修正_formatCurrency方法

修改方法逻辑,正确返回格式化后的货币字符串:

final NumberFormat currencyFormatter = NumberFormat.currency(symbol: '\$', decimalDigits: 2);
String _formatCurrency(double value) {
  // 直接传入double类型数值,用NumberFormat格式化
  return currencyFormatter.format(value);
}

注意:将参数类型从String改为double,因为初始化时传入的是widget.salePrice(double类型),无需先转字符串再处理。

2. 修复calculateCommission方法

在解析前先清理货币字符串中的非数字字符(保留小数点):

void calculateCommission() {
  if (salePriceController.text.isNotEmpty &&
      commissionRateController.text.isNotEmpty) {
    try {
      // 清理售价字符串:移除$和逗号,只保留数字和小数点
      String cleanedSalePrice = salePriceController.text.replaceAll(RegExp(r'[\$,]'), '');
      double salePrice = double.parse(cleanedSalePrice);
      
      double commissionRate = double.parse(commissionRateController.text);

      double commissionAmount = (salePrice * commissionRate) / 100;
      setState(() {
        commission = commissionAmount;
      });
    } catch (e) {
      print(e);
      // 可以在这里添加错误提示,比如显示SnackBar
    }
  } else {
    // 处理空字段,比如显示提示
  }
}

3. 修正initState初始化逻辑

因为_formatCurrency参数改为double类型,所以初始化时直接传入widget.salePrice:

@override
void initState() {
  super.initState();
  salePriceController.text = _formatCurrency(widget.salePrice);
}

4. 可选:添加输入格式化(优化用户体验)

给售价TextField添加TextInputFormatter,限制用户只能输入数字和小数点,同时自动格式化货币:

TextField(
  controller: salePriceController,
  decoration: const InputDecoration(labelText: 'Sale Price (\$)'),
  keyboardType: TextInputType.numberWithOptions(decimal: true),
  inputFormatters: [
    FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d{0,2}')),
    // 可选:添加自动货币格式化的输入 formatter
    // CurrencyInputFormatter(symbol: '\$'), // 需自定义或使用第三方包
  ],
)

完整修正后的代码

class CommissionCalculatorPopup {
  static void showCommissionCalculator(BuildContext context, double salePrice) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return CommissionCalculatorDialog(salePrice: salePrice);
      },
    );
  }
}

class CommissionCalculatorDialog extends StatefulWidget {
  final double salePrice;

  const CommissionCalculatorDialog({required this.salePrice, super.key});

  @override
  State<CommissionCalculatorDialog> createState() =>
      _CommissionCalculatorDialogState();
}

class _CommissionCalculatorDialogState
    extends State<CommissionCalculatorDialog> {
  TextEditingController salePriceController = TextEditingController();
  TextEditingController commissionRateController = TextEditingController();
  double commission = 0.0;

  final NumberFormat currencyFormatter = NumberFormat.currency(symbol: '\$', decimalDigits: 2);
  
  String _formatCurrency(double value) {
    return currencyFormatter.format(value);
  }

  @override
  void initState() {
    super.initState();
    salePriceController.text = _formatCurrency(widget.salePrice);
  }

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text(
        'Commission Calculator',
        style: TextStyle(fontSize: 8.sp),
      ),
      content: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          TextField(
            controller: salePriceController,
            decoration: const InputDecoration(labelText: 'Sale Price (\$)'),
            keyboardType: TextInputType.numberWithOptions(decimal: true),
          ),
          TextField(
            controller: commissionRateController,
            decoration: const InputDecoration(labelText: 'Commission Rate (%)'),
            keyboardType: TextInputType.numberWithOptions(decimal: true),
          ),
          SizedBox(height: 20.sp),
          ElevatedButton(
            onPressed: calculateCommission,
            child: const Text('Calculate Commission'),
          ),
          SizedBox(height: 20.sp),
          Text(
            'Commission: \$${commission.toStringAsFixed(2)}',
            style: TextStyle(fontSize: 8.sp),
          ),
        ],
      ),
      actions: [
        TextButton(
          onPressed: () {
            Navigator.of(context).pop();
          },
          child: const Text('Close'),
        ),
      ],
    );
  }

  void calculateCommission() {
    if (salePriceController.text.isNotEmpty &&
        commissionRateController.text.isNotEmpty) {
      try {
        String cleanedSalePrice = salePriceController.text.replaceAll(RegExp(r'[\$,]'), '');
        double salePrice = double.parse(cleanedSalePrice);
        double commissionRate = double.parse(commissionRateController.text);

        double commissionAmount = (salePrice * commissionRate) / 100;
        setState(() {
          commission = commissionAmount;
        });
      } catch (e) {
        print(e);
        // 可添加错误提示,例如:
        // ScaffoldMessenger.of(context).showSnackBar(
        //   SnackBar(content: Text('Invalid input: $e')),
        // );
      }
    } else {
      // 处理空字段
      // ScaffoldMessenger.of(context).showSnackBar(
      //   const SnackBar(content: Text('Please fill all fields')),
      // );
    }
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 05:03:10