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

问题描述 投票:0回答:2

我有一个带有一些输入的表格。我使用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
2个回答
0
投票

我想也许你需要的是TextInputFormatter

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

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


0
投票

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

我相信没有什么禁止你在验证中更新状态,但也许它会变得不那么有条理。 :)

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

我想最好的方法来完成你需要的是使用TextInputFormatterWhitelistingTextInputFormatter,检查出来:

注意TextInputType.numberWithOptions(decimal: true),如果用户粘贴“-100,00”,它将变为100.0 - 这对于一个价格来说没问题,但一般来说不是双值。

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

© www.soinside.com 2019 - 2024. All rights reserved.