Flutter 仅允许输入3位十进制数字
我想强制用户只输入一个点和3个小数点 我发现代码如下:Flutter 仅允许输入3位十进制数字,flutter,Flutter,我想强制用户只输入一个点和3个小数点 我发现代码如下: class NumberRemoveExtraDotFormatter extends TextInputFormatter { NumberRemoveExtraDotFormatter({this.decimalRange = 3}) : assert(decimalRange == null || decimalRange > 0); final int decimalRange; @override Tex
class NumberRemoveExtraDotFormatter extends TextInputFormatter {
NumberRemoveExtraDotFormatter({this.decimalRange = 3}) : assert(decimalRange == null || decimalRange > 0);
final int decimalRange;
@override
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
var nValue = newValue.text;
var nSelection = newValue.selection;
Pattern p = RegExp(r'(\d+\.?)|(\.?\d+)|(\.?)');
nValue = p.allMatches(nValue).map<String>((Match match) => match.group(0)).join();
if (nValue.startsWith('.')) {
nValue = '0.';
} else if (nValue.contains('.')) {
if (nValue.substring(nValue.indexOf('.') + 1).length > decimalRange) {
nValue = oldValue.text;
} else {
if (nValue.split('.').length > 2) {
var split = nValue.split('.');
nValue = split[0] + '.' + split[1];
}
}
}
nSelection = newValue.selection.copyWith(
baseOffset: math.min(nValue.length, nValue.length + 1),
extentOffset: math.min(nValue.length, nValue.length + 1),
);
return TextEditingValue(text: Utils.addCommad(nValue), selection: nSelection, composing: TextRange.empty);
}
}
class NumberRemoveExtraDotFormatter扩展了TextInputFormatter{
NumberRemoveExtraDotFormatter({this.decimalRange=3}):断言(decimalRange==null | | decimalRange>0);
最终整数小数范围;
@凌驾
TextEditingValue formatEditUpdate(TextEditingValue旧值,TextEditingValue新值){
var nValue=newValue.text;
var nSelection=newValue.selection;
模式p=RegExp(r'(\d+\.?)|(\.?\d+)|(\.?));
nValue=p.allMatches(nValue).map((Match-Match)=>Match.group(0)).join();
if(nValue.startsWith('.')){
nValue='0';
}else if(nValue.contains('.')){
if(nValue.substring(nValue.indexOf('.')+1.length>decimalRange){
nValue=oldValue.text;
}否则{
如果(nValue.split('.')。长度>2){
var split=n值分割('.');
nValue=split[0]+'.+split[1];
}
}
}
nSelection=newValue.selection.copyWith(
baseOffset:math.min(nValue.length,nValue.length+1),
extendtoffset:math.min(nValue.length,nValue.length+1),
);
返回TextEditingValue(文本:Utils.addCommad(nValue),选择:nSelection,组合:TextRange.empty);
}
}
但问题是,当用户输入超过3个小数点,然后想要删除时,它不会。因为数字保存在textformfield中,它们需要删除,直到它们达到3个小数点,而且当从输入光标的中间键入时,它们也会跳到末尾
另外,若用户输入的小数点超过3,我想将数字从右边移出
如何实现这一点?尝试使用以下方法:
filteringtExputFormatter(RegExp(r'(^[0-9]*(?:\[0-9]{0,3})))),allow:true),
基本上,正则表达式将尝试匹配0个或更多出现的数字,后跟可选的十进制数,后跟十进制数后最多3个数字。您可以将其修改为同时使用负值
^(?:\-)?[0-9]*(?:\.[0-9]{0,3})$
如果您只想强制用户只输入一个点和三个小数点,这可能会起作用
FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d{0,3}'))
根据你的评论:
当输入最大分数位数为0的长数字时,将添加错误的数字。=>这并不取决于最大分数位数。它总是发生 我认为NumberFormat中有一些意外的行为,我将其更改为custom方法,现在它支持负数
class NumberInputFormatter extends TextInputFormatter {
final int maximumFractionDigits;
NumberInputFormatter({
this.maximumFractionDigits = 3,
}) : assert(maximumFractionDigits != null && maximumFractionDigits >= 0);
@override
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
var newText = newValue.text;
var selectionOffset = newValue.selection.extent.offset;
bool isNegative = false;
if (newText.startsWith('-')) {
newText = newText.substring(1);
isNegative = true;
}
if (newText.isEmpty) {
return newValue;
}
if (newText.indexOf('.') != newText.lastIndexOf('.')) {
// inputted more than one dot.
return oldValue;
}
if (newText.startsWith('.') && maximumFractionDigits > 0) {
newText = '0$newText';
selectionOffset += 1;
}
while (newText.length > 1 && !newText.startsWith('0.') && newText.startsWith('0')) {
newText = newText.substring(1);
selectionOffset -= 1;
}
if (_decimalDigitsOf(newText) > maximumFractionDigits) {
// delete the extra digits.
newText = newText.substring(0, newText.indexOf('.') + 1 + maximumFractionDigits);
}
if (newValue.text.length == oldValue.text.length - 1 &&
oldValue.text.substring(newValue.selection.extentOffset, newValue.selection.extentOffset + 1) == ',') {
// in this case, user deleted the thousands separator, we should delete the digit number before the cursor.
newText = newText.replaceRange(newValue.selection.extentOffset - 1, newValue.selection.extentOffset, '');
selectionOffset -= 1;
}
if (newText.endsWith('.')) {
// in order to calculate the selection offset correctly, we delete the last decimal point first.
newText = newText.replaceRange(newText.length - 1, newText.length, '');
}
int lengthBeforeFormat = newText.length;
newText = _removeComma(newText);
if (double.tryParse(newText) == null) {
// invalid decimal number
return oldValue;
}
newText = _addComma(newText);
selectionOffset += newText.length - lengthBeforeFormat; // thousands separator newly added
if (maximumFractionDigits > 0 && newValue.text.endsWith('.')) {
// decimal point is at the last digit, we need to append it back.
newText = '$newText.';
}
if (isNegative) {
newText = '-$newText';
}
return TextEditingValue(
text: newText,
selection: TextSelection.collapsed(offset: min(selectionOffset, newText.length)),
);
}
static int _decimalDigitsOf(String text) {
var index = text?.indexOf('.') ?? -1;
return index == -1 ? 0 : text.length - index - 1;
}
static String _addComma(String text) {
StringBuffer sb = StringBuffer();
var pointIndex = text.indexOf('.');
String integerPart;
String decimalPart;
if (pointIndex >= 0) {
integerPart = text.substring(0, pointIndex);
decimalPart = text.substring(pointIndex);
} else {
integerPart = text;
decimalPart = '';
}
List<String> parts = [];
while (integerPart.length > 3) {
parts.add(integerPart.substring(integerPart.length - 3));
integerPart = integerPart.substring(0, integerPart.length - 3);
}
parts.add(integerPart);
sb.writeAll(parts.reversed, ',');
sb.write(decimalPart);
return sb.toString();
}
static String _removeComma(String text) {
return text.replaceAll(',', '');
}
}
class NumberInputFormatter扩展了TextInputFormatter{
最终整数最大分数位数;
数字输入格式化程序({
此.maximumFractionDigits=3,
}):assert(maximumFractionDigits!=null&&maximumFractionDigits>=0);
@凌驾
TextEditingValue formatEditUpdate(TextEditingValue旧值,TextEditingValue新值){
var newText=newValue.text;
var selectionOffset=newValue.selection.extent.offset;
bool为阴性=假;
if(newText.startsWith('-')){
newText=newText.substring(1);
isNegative=true;
}
if(newText.isEmpty){
返回新值;
}
if(newText.indexOf('.')!=newText.lastIndexOf('.')){
//输入多个点。
返回旧值;
}
if(newText.startsWith('.')&&maximumFractionDigits>0){
newText='0$newText';
selectionOffset+=1;
}
而(newText.length>1&&!newText.startsWith('0')&&newText.startsWith('0')){
newText=newText.substring(1);
selectionOffset-=1;
}
if(_decimaldigitof(newText)>maximumFractionDigits){
//删除多余的数字。
newText=newText.substring(0,newText.indexOf('.')+1+最大分数位数);
}
如果(newValue.text.length==oldValue.text.length-1&&
oldValue.text.substring(newValue.selection.extendtoffset,newValue.selection.extendtoffset+1)=','){
//在这种情况下,用户删除了千位分隔符,我们应该删除光标前的数字。
newText=newText.replaceRange(newValue.selection.extendtoffset-1,newValue.selection.extendtoffset“”);
selectionOffset-=1;
}
if(newText.endsWith('.')){
//为了正确计算选择偏移量,我们首先删除最后一个小数点。
newText=newText.replaceRange(newText.length-1,newText.length“”);
}
int lengthBeforeFormat=newText.length;
新文本=_removeComma(新文本);
if(double.tryParse(newText)==null){
//无效的十进制数
返回旧值;
}
新文本=_addComma(新文本);
selectionOffset+=newText.length-lengthBeforeFormat;//新添加的千位分隔符
if(maximumFractionDigits>0&&newValue.text.endsWith('.')){
//小数点在最后一位,我们需要把它加回去。
newText=“$newText”;
}
如果(为负){
newText='-$newText';
}
返回TextEditingValue(
文本:新文本,
选择:TextSelection.Closed(偏移量:min(selectionOffset,newText.length)),
);
}
静态整数小数位数(字符串文本){
变量索引=文本?.indexOf('.')??-1;
返回索引==-1?0:text.length-index-1;
}
静态字符串\u add逗号(字符串文本){
StringBuffer sb=StringBuffer();
var pointIndex=text.indexOf('.');
字符串整数部分;
弦分母;
如果(点索引>=0){
integerPart=text.substring(0,pointIndex);
decimalPart=text.substring(pointIndex);
}否则{
inte
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:math' as math;
class DecimalChecker extends TextInputFormatter {
DecimalChecker({this.decimalRange = 3})
: assert(decimalRange == null || decimalRange > 0);
final int decimalRange;
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
String valueTxt = newValue.text;
TextSelection valueSet = newValue.selection;
var newlength = newValue.text.length;
var oldlength = oldValue.text.length;
if (oldlength < newlength) {
Pattern p = RegExp(r'(\d+\.?)|(\.?\d+)|(\.?)');
valueTxt = p
.allMatches(valueTxt)
.map<String>((Match match) => match.group(0))
.join();
print("------>");
if (valueTxt.startsWith('.')) {
valueTxt = '0.';
} else if (valueTxt.contains('.')) {
if (valueTxt.substring(valueTxt.indexOf('.') + 1).length >
decimalRange) {
valueTxt = oldValue.text;
} else {
if (valueTxt.split('.').length > 2) {
List<String> split = valueTxt.split('.');
valueTxt = split[0] + '.' + split[1];
}
}
}
valueSet = newValue.selection.copyWith(
baseOffset: math.min(valueTxt.length, valueTxt.length + 1),
extentOffset: math.min(valueTxt.length, valueTxt.length + 1),
);
return TextEditingValue(
text: valueTxt, selection: valueSet, composing: TextRange.empty);
} else {
return TextEditingValue(
text: valueTxt, selection: valueSet, composing: TextRange.empty);
}
}
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'My Decimal Check App'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
TextEditingController numberController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0),
child: TextField(
controller: numberController,
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [DecimalChecker()],
decoration: InputDecoration(
hintText: "Please enter Number",
),
),
),
],
),
),
);
}
}