我有一个带有一些输入的表格。我使用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
。
我要做的是,当调用验证器时,我想检查任何逗号的输入字符串,然后如果它们存在,则用点替换它们,并相应地更新表单值。
我的问题是 - 我们真的可以在验证器中更新表单状态吗?
我想也许你需要的是TextInputFormatter
。
这是docs https://docs.flutter.io/flutter/services/TextInputFormatter-class.html的链接
您可以使用预先存在的格式化程序作为将逗号转换为点的参考。
我认为你不需要更新validator
中的状态。我只会使用save
事件来更新状态。这样就可以非常清楚状态更新的位置。
我相信没有什么禁止你在验证中更新状态,但也许它会变得不那么有条理。 :)
我想最好的方法来完成你需要的是使用TextInputFormatter
和WhitelistingTextInputFormatter
,检查出来:
注意TextInputType.numberWithOptions(decimal: true)
,如果用户粘贴“-100,00”,它将变为100.0 - 这对于一个价格来说没问题,但一般来说不是双值。
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),
),
);
}
}