如何使用MaskTextInputFormatter实现月份的两位数字正则掩码验证?
解决Flutter生日输入掩码中月份正则的问题
你推测的原因完全正确:MaskTextInputFormatter的filter是对单个占位符字符做校验的,你给m的正则是匹配完整两位月份(01-12)的规则,输入第一个字符时根本无法满足该正则,所以导致月份部分无法输入任何内容。
以下是两种可行的实现方法:
方案一:拆分月份占位符,分位设置单字符正则
把掩码中的mm拆分为两个不同的占位符(比如m1和m2),分别设置符合单字符输入规则的正则,先保证用户能正常输入,后续再做整体月份合法性校验:
MaskTextInputFormatter _birthdayFormatter = MaskTextInputFormatter( mask: 'dd/m1m2/yyyy', filter: { 'd': RegExp(r'[0-9]'), 'm1': RegExp(r'[01]'), // 月份十位仅允许输入0或1 'm2': RegExp(r'[0-9]'), // 月份个位先允许0-9,后续可补充整体校验 'y': RegExp(r'[0-9]') }, type: MaskAutoCompletionType.lazy );
使用这个配置后,用户可以正常输入月份,你可以在表单提交或输入内容变化时,提取出m1m2拼接的字符串,校验是否属于01-12的合法范围。
方案二:自定义TextInputFormatter(实时精准控制)
如果需要实时校验月份的合法性,自定义TextInputFormatter是更灵活的选择,示例代码如下:
class BirthdayInputFormatter extends TextInputFormatter { @override TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { final text = newValue.text; String formattedText = ''; int cursorPosition = newValue.selection.end; // 过滤掉非数字字符 final digits = text.replaceAll(RegExp(r'[^0-9]'), ''); // 自动添加日期分隔符 for (int i = 0; i < digits.length; i++) { if (i == 2) formattedText += '/'; if (i == 4) formattedText += '/'; formattedText += digits[i]; // 同步调整光标位置 if (i < cursorPosition && (i == 1 || i == 3)) { cursorPosition++; } } // 实时校验月份合法性(当输入到第4位及以上时) if (digits.length >= 4) { final month = digits.substring(2, 4); if (int.tryParse(month) == null || int.parse(month) < 1 || int.parse(month) > 12) { // 月份不合法,拒绝本次输入 return oldValue; } } return TextEditingValue( text: formattedText, selection: TextSelection.collapsed(offset: cursorPosition.clamp(0, formattedText.length)), ); } }
使用时直接将其添加到TextField的inputFormatters列表中即可:
TextField( inputFormatters: [BirthdayInputFormatter()], decoration: InputDecoration(hintText: 'dd/mm/yyyy'), )
这个自定义格式化器会自动添加/分隔符,并且实时校验月份的合法性,不合法的输入会被直接拒绝。
内容的提问来源于stack exchange,提问作者Joaquín Varela
相关产品推荐
相关产品推荐

