【问题标题】:Flutter - update form state from validatorFlutter - 从验证器更新表单状态
【发布时间】:2019-08-21 02:50:27
【问题描述】:

我有一个带有一些输入的表单。我正在使用GlobalKey<FormState> 来处理提交和验证等。

其中一个字段应该接受双重输入,所以我通过尝试将输入值解析为双重来验证这一点:

return TextFormField(
  decoration: InputDecoration(labelText: 'Price'),
  keyboardType: TextInputType.number,
  validator: (String value) {
    double _parsedValue = double.tryParse(value);
    if (_parsedValue == null) {
      return "Please input a number";
    }
  },
  onSaved: (String value) {
    setState(() {
      _price = double.parse(value);
    });
  },
);

现在按预期工作。但是,如果用户输入例如 9,99 会失败,因为解析需要 9.99

我想要做的是,当调用验证器时,我想检查输入字符串中是否有逗号,然后如果它们存在,则用点替换它们,并相应地更新表单值.

我的问题是 - 我们真的可以从验证器中更新表单状态吗?

【问题讨论】:

    标签: dart flutter


    【解决方案1】:

    您好,您解决了吗? 我会重新考虑你在这个问题上的策略。 也许您需要的是一个观察者函数,它在用户输入时触发,然后查看逗号并将其更改为点。 TextFormField 有一个内置函数, onEditingCompletedonFieldSubmitted 可以运行您必须在运行验证之前进行检查的功能。

    【讨论】:

      【解决方案2】:

      我认为您不需要更新validator 中的状态。我只会使用save 事件来更新状态。这样一来,状态更新的位置就非常清楚了。

      我相信没有什么能阻止你更新验证中的状态,但它可能会变得不那么有条理。 :)

      不能完全回答您的问题的解决方案

      我想完成你需要的最好方法是使用TextInputFormatterWhitelistingTextInputFormatter,看看吧:

      注意TextInputType.numberWithOptions(decimal: true),如果用户粘贴 "-100,00" ,它将变为 100.0 - 这对于 价格 来说是可以的,但对于一般的 double 值而言则不行。

      import 'package:flutter/material.dart';
      import 'package:flutter/services.dart';
      
      void main() => runApp(MyApp());
      
      class MyApp extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          return MaterialApp(
            title: 'ValidatorState',
            theme: ThemeData(primarySwatch: Colors.yellow),
            home: MyFormPage(),
          );
        }
      }
      
      class MyFormPage extends StatefulWidget {
        @override
        _MyFormPageState createState() => _MyFormPageState();
      }
      
      class _MyFormPageState extends State<MyFormPage> {
        final _formKey = GlobalKey<FormState>();
      
        double _price;
      
        void _save() {
          if (_formKey.currentState.validate()) {
            _formKey.currentState.save();
      
            Scaffold.of(_formKey.currentContext)
              .showSnackBar(SnackBar(content: Text('New price defined! ($_price)')));
          }
        }
      
        Widget _buildForm(BuildContext context) {
          return Container(
            padding: EdgeInsets.all(10.0),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                TextFormField(
                  inputFormatters: <TextInputFormatter>[
                    WhitelistingTextInputFormatter(RegExp("[0-9.]"))
                  ],
                  decoration: InputDecoration(labelText: 'Price'),
                  keyboardType: TextInputType.numberWithOptions(decimal: true),
                  validator: (String value) {
                    double _parsedValue = double.tryParse(value);
                    if (_parsedValue == null) {
                      return "Please input a valid number";
                    }
                    if (_parsedValue == 0.0) {
                      return "Please input a valid price";
                    }
                  },
                  onSaved: (String value) {
                    setState(() {
                      _price = double.tryParse(value);
                    });
                  },
                ),
                Text(""),
                RaisedButton(
                  child: Text("Save"),
                  color: Theme.of(context).primaryColor,
                  textColor: Theme.of(context).primaryTextTheme.title.color,
                  onPressed: _save,
                ),
                Text(""),
                TextFormField(
                  decoration: InputDecoration(labelText: 'Copy and Paste area'),
                ),
              ],
            ),
          );
        }  
      
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            appBar: AppBar(
              title: Text("Validator State"),
            ),
            body: Form(
              key:_formKey,
              child: _buildForm(context),
            ),
          );
        }
      }
      

      解答您的问题的解决方案

      但是,这与您描述的不完全一样。您想自动将, 替换为.。我会避免这样做,因为1,234.56 会转换为1.234.56,这是无效的。如果你只去掉逗号,你最终会得到1234.56,这是有效的。

      如果你真的想按你说的做,你必须使用TextEditingController 和一个函数来规范化文本数据。我制作了下面的示例,请查看 - 特别是 _priceController_parsePrice

      import 'package:flutter/material.dart';
      
      void main() => runApp(MyApp());
      
      class MyApp extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          return MaterialApp(
            title: 'ValidatorState',
            theme: ThemeData(primarySwatch: Colors.yellow),
            home: MyFormPage(),
          );
        }
      }
      
      class MyFormPage extends StatefulWidget {
        @override
        _MyFormPageState createState() => _MyFormPageState();
      }
      
      class _MyFormPageState extends State<MyFormPage> {
        final _formKey = GlobalKey<FormState>();
      
        TextEditingController _priceController;
      
        double _price;
      
        @override
        void initState() {
          super.initState();
          _priceController = TextEditingController();
        }
      
        @override
        void dispose() {
          _priceController?.dispose();
      
          super.dispose();
        }
      
        void _save() {
          if (_formKey.currentState.validate()) {
            _formKey.currentState.save();
      
            Scaffold.of(_formKey.currentContext)
              .showSnackBar(SnackBar(content: Text('New price defined! ($_price)')));
          }
        }
      
        double _parsePrice(String text) {
          var buffer = new StringBuffer();
          text.runes.forEach((int rune) {
            // acceptable runes are . or 0123456789
            if (rune == 46 || (rune >= 48 && rune <= 57)) buffer.writeCharCode(rune);
      
            // if we find a , we replace with a .
            if (rune == 44) buffer.writeCharCode(46);
          });    
          return double.tryParse(buffer.toString());
        }
      
        Widget _buildForm(BuildContext context) {
          return Container(
            padding: EdgeInsets.all(10.0),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                TextFormField(
                  controller: _priceController,
                  decoration: InputDecoration(labelText: 'Price'),
                  keyboardType: TextInputType.numberWithOptions(decimal: true),
                  validator: (String value) {
                    double _parsedValue = _parsePrice(value);
                    if (_parsedValue == null) {
                      return "Please input a valid number";
                    }
                    if (_parsedValue == 0.0) {
                      return "Please input a valid price";
                    }
                  },
                  onSaved: (String value) {
                    setState(() {
                      _price = _parsePrice(value);
                      _priceController.text = _price.toString();
                    });
                  },
                ),
                Text(""),
                RaisedButton(
                  child: Text("Save"),
                  color: Theme.of(context).primaryColor,
                  textColor: Theme.of(context).primaryTextTheme.title.color,
                  onPressed: _save,
                ),
              ],
            ),
          );
        }  
      
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            appBar: AppBar(
              title: Text("Validator State"),
            ),
            body: Form(
              key:_formKey,
              child: _buildForm(context),
            ),
          );
        }
      }
      
      

      【讨论】:

        【解决方案3】:

        我想也许你需要的是TextInputFormatter

        这里是文档的链接https://docs.flutter.io/flutter/services/TextInputFormatter-class.html

        有一些预先存在的格式化程序可以用作将逗号转换为点的参考。

        【讨论】:

        • 我已经有一段时间没有做颤振了,但这似乎是处理我所要求的正确方法,谢谢!
        • 这个答案解决了问题正文中提出的问题,但没有解决标题中提出的一般问题。在我的情况下,如果验证成功,我必须显示 TextFormField helperText,所以我必须调用setState()。现在我使用的是 - 而不是 validator(使用 AutovalidateMode.onUserInteraction) - InputDecoration.onChanged,但即使调用 formState.validate(),我也失去了验证的能力
        猜你喜欢
        • 2019-11-30
        • 2015-03-23
        • 1970-01-01
        • 1970-01-01
        • 2020-10-10
        • 1970-01-01
        • 2021-03-19
        • 2018-10-16
        • 1970-01-01
        相关资源
        最近更新 更多