概述

#

要控制 LengthLimitingTextInputFormattermaxLength 的行为,请使用 maxLengthEnforcement 而非已弃用的 maxLengthEnforced

背景

#

maxLengthEnforced 参数曾用于决定文本字段在达到 maxLength 限制时是截断输入值,还是(对于 TextFieldTextFormField)在用户输入长度超过 maxLength 时显示字符计数的警告消息。

然而,为了输入 CJK 字符,某些输入法需要用户在文本字段中输入一系列拉丁字符,然后将这些字符转换为所需的 CJK 字符(这称为*文本组合*)。拉丁字符序列通常比生成的 CJK 字符长,因此为文本字段设置硬性的最大字符限制可能会导致用户因 maxLength 字符限制而无法正常完成文本组合。

文本组合也被某些输入法用来指示被高亮显示的组合区域内的文本正在被积极编辑,即使在输入拉丁字符时也是如此。例如,Android 上的 Gboard 英文键盘(与其他许多 Android 输入法一样)会将当前单词置于一个组合区域中。

为了改善这些场景下的输入体验,引入了一个新的三态枚举 MaxLengthEnforcement。其值描述了在使用 LengthLimitingTextInputFormatter 应用活动组合区域时支持的策略。一个使用此枚举的新 maxLengthEnforcement 参数已添加到文本字段中,以取代布尔值 maxLengthEnforced 参数。通过新的枚举参数,开发人员可以根据文本字段期望的内容类型选择不同的策略。

有关更多信息,请参阅 maxLengthMaxLengthEnforcement 的文档。

maxLengthEnforcement 参数的默认值是从应用程序的 TargetPlatform 推断的,以符合平台的约定。

变更说明

#
  • 添加了使用新的枚举类型 MaxLengthEnforcementmaxLengthEnforcement 参数,作为 TextFieldTextFormFieldCupertinoTextFieldLengthLimitingTextInputFormatter 类中已弃用的布尔值 maxLengthEnforced 参数的替代品。

迁移指南

#

推荐使用当前平台的默认行为,因为这对于用户来说是最熟悉的行为。

maxLengthEnforcement 的默认值

#
  • Android、Windows:MaxLengthEnforcement.enforced。这些平台的原生行为是强制执行的。无论用户是否在组合输入,输入的值都将被截断。
  • iOS、macOS:MaxLengthEnforcement.truncateAfterCompositionEnds。这些平台没有“最大长度”功能,因此要求开发人员自行实现该行为。在这些平台上似乎没有出现标准的约定。我们选择允许组合文本超出最大长度,以避免破坏 CJK 输入。
  • Web 和 Linux:MaxLengthEnforcement.truncateAfterCompositionEnds。虽然这些平台没有标准(并且存在许多行为冲突的实现),但常见的约定似乎是默认允许组合文本超出最大长度。
  • Fuchsia:MaxLengthEnforcement.truncateAfterCompositionEnds。此平台尚无平台约定,因此我们选择默认采用最不可能导致数据丢失的约定。

始终强制执行限制

#

要强制执行当值达到限制时始终截断的限制(例如,输入验证码时),请在可编辑文本字段中使用 MaxLengthEnforcement.enforced

当与依赖文本组合的输入法一起使用时,此选项可能会导致用户体验不佳。当文本字段期望任意用户输入(可能包含 CJK 字符)时,请考虑使用 truncateAfterCompositionEnds 选项。有关更多信息,请参阅 背景 部分。

迁移前的代码

dart
TextField(maxLength: 6)

dart
TextField(
  maxLength: 6,
  maxLengthEnforced: true,
)

迁移后的代码

dart
TextField(
  maxLength: 6,
  maxLengthEnforcement: MaxLengthEnforcement.enforced,
)

不强制执行限制

#

要在 TextField 中显示最大长度错误,但在超过限制时截断,请使用 MaxLengthEnforcement.none 而非 maxLengthEnforced: false

迁移前的代码

dart
TextField(
  maxLength: 6,
  maxLengthEnforced: false,
)

迁移后的代码

dart
TextField(
  maxLength: 6,
  maxLengthEnforcement: MaxLengthEnforcement.none,
)

对于无法显示错误消息的 CupertinoTextField,只需不设置 maxLength 值。

迁移前的代码

dart
CupertinoTextField(
  maxLength: 6,
  maxLengthEnforced: false,
)

迁移后的代码

dart
CupertinoTextField()

强制执行限制,但不是针对组合文本

#

为避免在用户使用组合输入文本时截断文本,请指定 MaxLengthEnforcement.truncateAfterCompositionEnds。此行为允许使用组合区域大于最终文本的输入法(例如,中文、日文和韩文(CJK)文本很常见)暂时忽略限制,直到编辑完成。

Android 上的 Gboard 英文键盘(以及许多其他 Android 输入法)会为正在输入的单词创建一个组合区域。当在 truncateAfterCompositionEnds 文本字段中使用时,用户不会在 maxLength 限制处立即停止。如果您确信文本字段不会与使用暂时性长组合区域(如 CJK 文本)的输入法一起使用,请考虑 enforced 选项。

实现代码

dart
TextField(
  maxLength: 6,
  maxLengthEnforcement: MaxLengthEnforcement.truncateAfterCompositionEnds, // Temporarily lifts the limit.
)

请注意,不要假设输入不会使用组合区域

#

当针对特定区域设置时,人们很容易认为所有用户都会满意于该区域的输入。例如,针对英语社区的论坛软件可能会被假定为只需要处理英语文本。然而,这种假设通常是错误的。例如,也许英语论坛的参与者想讨论日本动漫或越南菜。也许其中一位参与者是韩国人,更喜欢用他们的母语表意文字来表达名字。因此,自由格式字段应很少使用 enforced 值,而应尽可能优先使用 truncateAfterCompositionEnds 值。

时间线

#

已在版本:v1.26.0-1.0.pre 中发布
稳定版本:2.0.0

参考资料

#

设计文档

API 文档

相关问题

相关 PR

  • PR 63754: 修复 TextField 在组合和 maxLength 设置时崩溃的问题
  • PR 68086: 引入 MaxLengthEnforcement