Flutter — 文本为什么可以被编辑?如何自定义编辑的行为?

前言:

上一篇文章中,我们讲解了Flutter文本的组成部分和Flutter 文本渲染到屏幕上的逻辑。文本的输出我们已经分析完成了,那么文本的输入又是怎么样的呢?在Flutter中,我们知道文本的输入可以通过TextField等组件将文字输入到App中,但是它背后的原理是什么呢,为什么可以编辑文本呢?在这一篇文章中,就让我们从Flutter的可编辑文本的实现原理,再到自定义可编辑的文本...希望能对你认识Flutter的文本编辑有所帮助。

注:本文的涉及较多文本编辑的核心逻辑,和大量的功能实践,建议收藏!

TextField背后的存在


在开始具体的分析前,大家可以先看下上面这张流程图,如果你和我一样,好奇Flutter的文本渲染和文本编辑之间有哪些联系,那么当你看完上图后会发现,从TextPainter开始就是相同的了,这也意味着,我们可以只分析TextPainter上层的部分。

组件层

每当我们想要在Flutter中进行文本的输入或者编辑时,我们通常会首先想到TextField这个组件,除了iOS和macOS外的系统都会使用它,它是属于Material库的一部分,和它对应的是Cupertino库中的CupertinoTextField

除了这两个组件,大家可能还会想到TextFormField这个组件,但是它其实只是一个能帮助你更快速的实现一些类似保存逻辑的功能,它本质上还是TextField

TextFieldCupertinoTextField它们是有状态的组件。它们需要处理焦点、手势、鼠标悬停...等内容。但是无论是使用 TextField 还是 CupertinoTextField 最后都会创建EditableText

  • 来自TextField 类 - 材料库 - Dart API

    EditableText,它是 TextField核心的原始文本编辑控件。EditableText小部件很少直接使用,除非您正在实现完全不同的设计语言,例如 Cupertino。

当本文写到这里时,发现郭哥已经很详细的分析了TextField的内部原理,对于TextField的内部原理本文就不过多赘述了。

推荐阅读:Flutter 快速解析 TextField 的内部原理 — @恋猫de小郭

如何自定义编辑的行为?

自定义的编辑行为主要为下面几块部分

  • 格式化输入框的数据
  • 自定义文本选中范围
  • 自定义光标位置

通过TextInputFormatter格式化输入框的数据

在日常开发中,我们经常会碰到需要用户提交身份证信息,电话号码,银行卡号码等需求,在输入框中获取有效的格式化的数据是必不可少的。在自定义后,能使提交流程简化,大幅度减少错误信息,提高用户体验。

在Flutter中可以使用TextInputFormatter这个类获取到有效的格式化的数据,TextField可以使用它在编辑文本时纠正文本格式。

基本使用:

Flutter提供了两个基础的TextInputFormatter

  • FilteringTextInputFormatter — 创建一个格式化工具,常与正则表达式一起使用。
  • LengthLimitingTextInputFormatter — 只允许输入一定数量的字符。

自定义TextInputFormatter

在日常开发时,仅仅只靠正则表达式是不够的,我们需要针对需求创建自定义的格式化工具。我们可以扩展TextInputFormatter实现formatEditUpdate方法来实现自定义的TextInputFormatter

为了有更多的扩展性,此处实现一个格式化模板,只需传入xxx-xxxx-xxxx的手机号格式即可,若有其他需求,如银行卡号码等,只需传入它的格式。

使用

若需求改变只需要传入不同的model,和separator就可以了。

在开发需求中,碰到需要限制金额等,限制输入数字大小的需求时,我们也一样可以通过自定义TextInputFormatter来实现。设置好限制的大小后,如果输入的值超过这个数字,则值自动等于限制的大小。

通过TextInputFormatter我们可以很容易的实现各种格式化的工具,还有很多的功能大家可以自行探索。

自定义文本选中范围

自定义文本可以很大程度上提高用户的体验(前提是处理好的情况下),例如在一段长文本中,可以通过文本选中范围,快速定位到需要的文本,然后对进行复制、删除、修改...等功能。

在Flutter中,我们可以通过设置TextFieldcontroller中的selection,来实现文本选中。

我们通过实现在一段文本中,快速定位选中姓名的例子,来看下怎样自定义文本选中范围。

自定义选中文本范围使用恰当的话,我相信可以给用户带来更好的体验!

自定义光标位置

与自定义选中文本范围一样,自定义光标的位置也会有更多的体验。自定义光标和自定义选中范围类似,这里就不在多说了。

TextEditingValue

分析了这么多TextEditingValue的应用,现在来分析它本身。

TextEditingValue有三个属性:

  • String textTextField显示的默认值,相当于TextEditingController中的text。因为查看源码就可以发现,TextEditingController里的text最终将会赋值给TextEditingValue.text

  • TextSelection selection:通过它可以知道当前选择的光标位置和选择范围,通过它也可以设置光标在换行时的精确位置。
  • TextRange composing:当前编辑单词的偏移量,当你输入某些文本时,它的下方会有下划线,同时,系统键盘的上方会有建议的文本,点击建议的文本即可替换下划线的文本。

可编辑的文本包含哪些内容呢?

我们已经知道在Flutter中,无论是使用 TextField 还是 CupertinoTextField 最后都会创建EditableText。也就是因为这个EditableText它将其他的可编辑的模块都集成了后,才能与系统键盘进行通信,才能在编辑文本时,出现光标、选中文本、可垂直滚动文本...

①具有样式、结构(文本高度)、文本对齐方式、本地化

EditableText中,具有样式:

通过StrutStyle已确保输入的文本符合分配的空间

文本具有对齐方式,默认为TextAlign.start,同时具有文本的方向textDirection,用于决定TextAlign.startTextAlign.end的值。

具有Locale,可以根据手机系统语言环境的不同,以不同的方式呈现文本。

②具有文本布局

EditableText的布局取决于maxLinesminLines和是否启用expands

  • 如果最大行数为一(默认为一),则将在一行上水平滚动。
  • 如果最大行数为空,则设置为最小行数,并垂直增长。
  • 如果最大行数大于 1,则按照最小行数进行布局,并垂直一行行增加,直到达到最大行数。
  • 当达到其最大高度,它将垂直滚动。
  • 如果启用了扩展,它会根据传入的约束调整大小。

EditableTextbuild方法中,嵌套了一层Scrollable,从而使文本可以垂直滚动显示多行文本,水平滚动以显示单行文本。

③对文本的更改有完整的处理流程

当文本的内容被更改时,EditableText首先会调用onChanged,通常会通知TextFiled去更改文本、光标或选择文本范围。

然后当用户按下键盘上的搜索或者发送键时,会调用onEditingComplete,将用户输入的内容提交给controller

EditableText通过_finalizeEditing处理键盘的操作。

最后当用户确认输入完成后,调用onSubmitted(大部分情况下,onSubmitted会在onChanged后调用)。

④当文本发生更改时,可通过updateEditingValue更新编辑的文本

如何更好的处理输入表单?

表单是我们用于收集用户数据的重要方式,它在应用程序中是不可或缺的组件(不只是移动端)。在用户的登录/注册、地址填写、身份信息填写...等场景中有着很重要的作用,那么在Flutter中,如何使用Form类带来更好的用户体验呢?

①通过Globalkey保存表单状态

Flutter Form组件是用于保存、验证表单文本的。

②将TextFormField添加到表单中

添加两个TextFormField,用于获取姓名和电话号码。

③分配FocusNode,使表单可以提交数据

④验证数据

在提交数据前,我们可以根据需求对数据进行验证,大家可以根据需求自己定义,例如:

尾述

在这篇文章中,我们知道了文本的编辑是包含了哪些内容,知道了如何自定义编辑的操作,也知道了如何更好的实现一个表单。但这也只是文本的输入编辑、文本的优化的冰山一角。在后续的文章中我也会和大家一起持续探索。希望这篇文章能对你有所帮助,有问题欢迎在评论区留言讨论~

参考&推荐阅读

Flutter中那些你需要知道的文本知识!

Flutter 快速解析 TextField 的内部原理 — @恋猫de小郭

参考链接

发布者

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注