Flutter-从验证器更新表单状态

时间:2019-03-30 08:45:42

标签: dart flutter

我有一个带有一些输入的表格。我正在使用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

我想做的是,当调用验证程序时,我想检查输入字符串中是否有任何逗号,如果存在,请用点代替它们,并相应地更新表单值

我的问题是-我们实际上可以从验证程序中更新表单状态吗?

3 个答案:

答案 0 :(得分:0)

我认为也许您需要的是TextInputFormatter

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

的链接

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

答案 1 :(得分:0)

我认为您不需要更新validator中的状态。我只会使用save事件来更新状态。这样,可以很清楚地知道状态在哪里更新。

我相信没有什么可以阻止您更新验证中的状态,但是也许它会变得井井有条。 :)

解决方案无法完全回答您的问题

我想最好的方式来完成您需要的是将TextInputFormatterWhitelistingTextInputFormatter一起使用,并检查一下:

请注意TextInputType.numberWithOptions(decimal: true),并且如果用户粘贴“ -100,00”,它将变为100.0-对于价格来说就可以了,但通常不建议使用double值

Using TextInputFormatter

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

validation example

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),
      ),
    );
  }
}

答案 2 :(得分:0)

您是否已解决此问题? 我会重新考虑您针对此问题的策略。 也许您需要的是一个观察者功能,当用户键入内容时触发该观察者功能,该功能然后查看逗号并将其更改为点。 TextFormField具有内置函数, open Template ;;onEditingCompleted可以运行您在运行验证之前必须进行检查的功能。