【问题标题】:Flutter TextFormField display value with NumberFormatFlutter TextFormField 用 NumberFormat 显示值
【发布时间】:2021-10-14 19:56:36
【问题描述】:

我希望能够使用NumberFormat('###,##0.00', 'en_US') 显示在 TextFormField 中输入的值。

转换没有问题,但在 TextFormField 中显示 formattedPrice 的值时遇到问题。我还想将 TextFormField 的默认值设置为'0.00'。在下面的示例代码中,TextFormField 将输入限制为只有一个十进制符号/分隔符和两个十进制值。

如果在输入期间 TextFormField 值中不存在小数,我可以不显示 .00 小数,但我希望在输入值时放置两位小数。

TextFormField value displayed when typing TextFormField value displayed when entered
123 123.00
123.5 123.50
123.54 123.54
12,345 12,345.00
12,345.6 12,345.60

最小复制

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _subscriptionFormKey = GlobalKey<FormState>();
  final _subscriptionPriceController = TextEditingController();
  NumberFormat numFormat = NumberFormat('###,###.00', 'en_US');
  NumberFormat numSanitizedFormat = NumberFormat('en_US');
  var currency = 'USD';

  void _validate() {
    if (_subscriptionFormKey.currentState!.validate()) {}
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Form(
        key: _subscriptionFormKey,
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: TextFormField(
            autofocus: true,
            inputFormatters: [
              FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d{0,2}')),
            ],
            keyboardType: TextInputType.numberWithOptions(decimal: true),
            validator: (cost) {
              if (cost == null || cost.isEmpty) {
                return 'Empty';
              }
              return null;
            },
            textInputAction: TextInputAction.next,

            /// TODO TextFormField default value
            /// I'd like to be to set '0.00' value by default
            controller: _subscriptionPriceController,
            decoration: InputDecoration(
              hintText: 'Price',
              prefixText:
                  NumberFormat.simpleCurrency(name: currency).currencySymbol,
            ),
            onChanged: (price) {
              /// TODO Display [formattedPrice] in TextFormField
              var formattedPrice = numFormat.format(double.parse(price));
              debugPrint('Formatted $formattedPrice');
              var numSanitized = numSanitizedFormat.parse(price);
              debugPrint('Sanitized: $numSanitized');
              _subscriptionPriceController.value = TextEditingValue(
                text: price,
                selection: TextSelection.collapsed(offset: price.length),
              );
            },
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _validate,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

更新:

感谢@Andrej 建议使用onFieldSubmitted() 而不是onChange()。我已经使用包含的修复程序更新了我的代码。我希望这将有助于其他因类似问题而受阻的开发人员。

修复代码:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _subscriptionFormKey = GlobalKey<FormState>();
  final _subscriptionPriceController = TextEditingController();
  final NumberFormat numFormat = NumberFormat('###,##0.00', 'en_US');
  final NumberFormat numSanitizedFormat = NumberFormat('en_US');
  var currency = 'USD';
  var defaultPrice = '0.00';

  void _validate() {
    if (_subscriptionFormKey.currentState!.validate()) {}
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Form(
        key: _subscriptionFormKey,
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: TextFormField(
            autofocus: true,
            inputFormatters: [
              FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d{0,2}')),
            ],
            keyboardType: TextInputType.numberWithOptions(decimal: true),
            validator: (cost) {
              if (cost == null || cost.isEmpty) {
                return 'Empty';
              }
              return null;
            },
            textInputAction: TextInputAction.next,

            /// Set TextFormField default value
            controller: _subscriptionPriceController..text = defaultPrice,
            decoration: InputDecoration(
              hintText: 'Price',
              prefixText:
                  NumberFormat.simpleCurrency(name: currency).currencySymbol,
            ),
            onTap: () {
              var textFieldNum = _subscriptionPriceController.value.text;
              var numSanitized = numSanitizedFormat.parse(textFieldNum);
              _subscriptionPriceController.value = TextEditingValue(
                /// Clear if TextFormField value is 0
                text: numSanitized == 0 ? '' : '$numSanitized',
                selection:
                    TextSelection.collapsed(offset: '$numSanitized'.length),
              );
            },
            onFieldSubmitted: (price) {
              /// Set value to 0 if TextFormField value is empty
              if (price == '') price = '0';
              final formattedPrice = numFormat.format(double.parse(price));
              debugPrint('Formatted $formattedPrice');
              _subscriptionPriceController.value = TextEditingValue(
                text: formattedPrice,
                selection:
                    TextSelection.collapsed(offset: formattedPrice.length),
              );
            },
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _validate,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

【问题讨论】:

    标签: flutter


    【解决方案1】:

    如果我理解正确,您希望在输入文本字段时格式化价格。

    如果是,只需将此代码添加到您的TextFormField

                onFieldSubmitted: (price) {
                  final formattedPrice = numFormat.format(double.parse(price));
                  debugPrint('Formatted $formattedPrice');
                  _subscriptionPriceController.value = TextEditingValue(
                    text: formattedPrice,
                    selection:
                        TextSelection.collapsed(offset: formattedPrice.length),
                  );
                },
    

    将初始值添加到文本字段:

    final _subscriptionPriceController = TextEditingController(text: '0.00');
    

    【讨论】:

    • 非常感谢!这为我节省了很多时间。使用onFieldSubmitted 代替onChanged((String value) { }) 效果最好。
    • 没问题,很高兴它帮助了你。祝你有美好的一天:)
    猜你喜欢
    • 1970-01-01
    • 2020-12-15
    • 2020-10-31
    • 1970-01-01
    • 2020-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-21
    相关资源
    最近更新 更多