首页 > 解决方案 > 验证并仅允许 TextField 中的日期和连字符 - MaskTextInputFormatter 不适用于手动更新文本

问题描述

我需要制作一个具有日期过滤器(dd-mm-yyyy)的TextField,我设法使用依赖项创建过滤器,mask_text_input_formatter: ^1.0.6如下所示

final TextEditingController _controller = TextEditingController();
var maskFormatter = new MaskTextInputFormatter(mask: '##-##-####');
...
child: TextField(
  controller: _controller,
  keyboardType: TextInputType.number,
  inputFormatters: [maskFormatter],
  onChanged: (text) {
    //
  },

因此,由于我找不到将文本屏蔽为有效日期的好方法(例如,没有 31-02-9299),我决定在onChanged回调中手动执行此操作并在某个时候更新文本,但只是使用基本 _controller.text = "1234";显示文本"1234"而不是"12-34".

可能是什么问题?

标签: flutterdart

解决方案


解决方案

对于您的特定用例,您可以尝试以下解决方案:

TextField(
    inputFormatters: [
        WhitelistingTextInputFormatter(RegExp(r"^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]|(?:Jan|Mar|May|Jul|Aug|Oct|Dec)))\1|(?:(?:29|30)(\/|-|\.)(?:0?[1,3-9]|1[0-2]|(?:Jan|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)(?:0?2|(?:Feb))\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9]|(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep))|(?:1[0-2]|(?:Oct|Nov|Dec)))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$")),
    ],
);

解释

您无法使用mask_text_input_formatterpub 验证所需的文本,因为它按 char 执行比较 char。因此,您只能使用正则表达式验证每个单独的字符。

要对 TextFormField 或 TextFormField 的文本执行手动验证TextField,则需要使用TextInputFormatter。更具体地说,使用BlacklistingTextInputFormatterWhitelistingTextInputFormatter。对于与您的问题不同的另一个示例,这里是如何限制两个点

正则表达式取自这个答案,这个特定正则表达式的测试用例可以在这里找到。

自动插入连字符

如果您想自动插入连字符,那么您需要在onChanged中工作。这是一个简单的例子

如果您要采用这种方法,您可以验证其中的文本,onChanged但您还必须使用有效文本重置最近更改的无效文本,因为onChanged在文本已更改后调用。因此,这是一种惰性验证,与BlacklistingTextInputFormatterWhitelistingTextInputFormatter不同,后者甚至在文本被修改之前就提供了急切的验证。


推荐阅读