Flutter中TextEditingController.fromValue方法的研究

最近在研究,自己试着用Flutter编写一个文本编辑的软件,只要和系统自带的记事本功能差不多就行。

心想,这不是很简单吗?直接使用TextField组件不就行了!

记事本的界面是占全屏,没有下划线,用代码设置一下样式就行。然后编写了如下代码:

return const Scaffold(
  body: SafeArea(
    child: Padding(
      padding: EdgeInsets.all(12.0),
        child: TextField(
          decoration: InputDecoration(
            border: InputBorder.none,
          ),
          maxLines: null,
         ),
       ),
     ),
  );

image

哈哈,果然简单!😄

然后我试着输入内容:

image

诶?😦第一行输入的字上移了。

碰到问题当然先百度一下,没有结果。然后又必应一下,还是没有。

🙁要不就找个现成的项目看看它是怎么写的。然后从Flutter上克隆了一个项目到本地,直冲写作的界面代码,然后发现了新大陆。

代码如下:

TextField(
  controller: TextEditingController.fromValue(
    TextEditingValue(
      // 设置内容
      text: notes,
      selection: TextSelection.fromPosition(
        TextPosition(
          affinity: TextAffinity.downstream,
          offset: notes.length,
        ),
      ),
    ),
  ),
  onChanged: (text) {
    setState(() {
      notes = text;
    });
  },
  maxLines: null,
  style: const TextStyle(),
  keyboardType: TextInputType.multiline,
  decoration: const InputDecoration.collapsed(hintText: '请输入您的内容'),
)

第一次发现TextEditingController还能这样写,以前都是先定义再初始化。

既然知道了,那就来好好研究研究这个fromValue方法。

TextEditingController.fromValue

TextEditingController.fromValue需要传入一个可为空的TextEditingValue对象。既然能为空,那就传入一个null先看看:

TextField(
  controller: TextEditingController.fromValue(null),
),

image

效果和不写这个参数是一样的。如果我们传入null值的话,这个值会被Flutter替换成TextEditingValue.empty

TextEditingController.fromValue方法可以直接传入一个TextEditingValue对象,也可以使用TextEditingValue.fromJson方法。

TextEditingValue

TextEditingValue有3个属性:

  • String text:TextField显示的默认值
  • TextSelection selection:文本选中范围
  • TextRange composing

text

TextEditingValue.text相当于``TextEditingController里的text参数。其实看源码可以发现,TextEditingController里的text最终将会赋值给TextEditingValue.text

TextEditingController({ String? text })
    : super(text == null ? TextEditingValue.empty : TextEditingValue(text: text));

selection

selection属性的默认值是TextSelection.collapsed(offset: -1),我们来看看是啥效果:

image

我们可以看到,光标瞬间移到最前面。我们修改一下数值看看:

TextSelection.collapsed(offset: 10)

image

通过上面的实验我们可以发现,offset可以用来设置光标的位置(当offset=0时和-1一样效果)。这还不算玩,我们试试删除这些文字会发生什么。

image

😦竟然从第10个字符开始,把后面的全都删除了。

TextSelection.collapsed中还有一个可选参数affinity,该参数可以传入两个不同的值:TextAffinity.upstream和TextAffinity.downstream(🤨下流???),其中 TextAffinity.downstream是默认值,我们改成TextAffinity.upstream一下看看是什么效果。。。试了一下,没有效果😦。。。如果有效果的话,会是如下样子:

image

该值用来设置,当字符串从offset处换行,光标应该显示在上一行还是下一行。

selection还可以传入TextSelection.fromPosition方法,该方法需要传入一个TextPosition对象的参数,该对象也有两个参数,和TextSelection.collapsed一模一样,效果也一样。

现在来说说TextSelection对象本身。

TextSelection

  • int baseOffset:开始的位置
  • int extentOffset:结束的位置
  • TextAffinity affinity:光标的位置
  • bool isDirectional:是否消除了其基础和范围的歧义(不懂可以直接忽略)

该对象可以用来设置文本的选择范围:

selection: const TextSelection(
  extentOffset: 5,
  baseOffset: 12,
),

image

其实,TextSelection.fromPosition是把TextSelection对象的 extentOffset 和 baseOffset赋值给了同一个数,而TextSelection.collapsed又是TextSelection.fromPosition的简化版。

composing

该值传入一个TextRange对象,该对象有两个属性:

  • int start:开始的位置
  • int end:结束的位置

我们来试试有什么效果:

composing: const TextRange(start: 8, end: 16),

image

我们设定的范围会有一条下划线。

composing的默认值为TextRange.empty,相当于把start和end的值设置成-1,而TextRange.collapsed方法是把start和end设置成相同的数值,所以显示效果回合TextRange.empty一样。

posted @ 2022-03-21 09:03  菠萝橙子丶  阅读(2042)  评论(0编辑  收藏  举报