概述

#

为了控制 `LengthLimitingTextInputFormatter` 中 `maxLength` 的行为,请使用 `maxLengthEnforcement` 而不是现在已弃用的 `maxLengthEnforced`。

背景

#

`maxLengthEnforced` 参数曾用于决定文本字段是否应在输入值达到 `maxLength` 限制时截断该值,或者(对于 `TextField` 和 `TextFormField`)是否应在用户输入长度超过 `maxLength` 时在字符计数中显示警告消息。

然而,为了输入中日韩(CJK)字符,一些输入法要求用户在文本字段中输入一系列拉丁字符,然后将这些序列转换为所需的中日韩字符(这被称为文本组合)。拉丁字符序列通常比最终的中日韩字符长,因此对文本字段设置严格的最大字符限制可能意味着用户由于 `maxLength` 字符限制而无法正常完成文本组合。

某些输入法也使用文本组合来指示突出显示的组合区域内的文本正在被主动编辑,即使在输入拉丁字符时也是如此。例如,安卓系统上 Gboard 的英文键盘(与安卓上的许多其他输入法一样)会将当前单词放入一个组合区域。

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

更多信息,请参阅 `maxLength``MaxLengthEnforcement` 的文档。

`maxLengthEnforcement` 参数的默认值是根据应用程序的 `TargetPlatform` 推断的,以符合平台的惯例

变更说明

#
  • 添加了一个使用新枚举类型 `MaxLengthEnforcement` 的 `maxLengthEnforcement` 参数,作为 `TextField`、`TextFormField`、`CupertinoTextField` 和 `LengthLimitingTextInputFormatter` 类上现在已弃用的布尔型 `maxLengthEnforced` 参数的替代。

迁移指南

#

建议使用当前平台的默认行为,因为这将是用户最熟悉的行为。

`maxLengthEnforcement` 的默认值

#
  • 安卓、Windows:`MaxLengthEnforcement.enforced`。这些平台的原生行为是强制执行的。无论用户是否使用组合输入,输入值都将被截断。
  • iOS、macOS:`MaxLengthEnforcement.truncateAfterCompositionEnds`。这些平台没有“最大长度”功能,因此要求开发者自行实现该行为。这些平台似乎没有形成标准惯例。我们选择允许组合超出最大长度以避免破坏中日韩输入。
  • Web 和 Linux:`MaxLengthEnforcement.truncateAfterCompositionEnds`。尽管这些平台没有标准(并且存在许多行为冲突的实现),但通常的惯例似乎是默认允许组合超出最大长度。
  • Fuchsia:`MaxLengthEnforcement.truncateAfterCompositionEnds`。该平台尚无平台惯例,因此我们选择默认采用最不可能导致数据丢失的惯例。

始终强制执行限制

#

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

当与依赖文本组合的输入法一起使用时,此选项可能会导致次优的用户体验。当文本字段预期可能包含中日韩字符的任意用户输入时,请考虑使用 `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)文本中常见的情况)暂时忽略限制,直到编辑完成。

安卓系统上 Gboard 的英文键盘(以及许多其他安卓输入法)会为正在输入的单词创建一个组合区域。当在 `truncateAfterCompositionEnds` 文本字段中使用时,用户不会立即在 `maxLength` 限制处被停止。如果您确信文本字段不会与使用临时长组合区域(例如中日韩文本)的输入法一起使用,请考虑 `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`