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,
),
),
),
);
哈哈,果然简单!😄
然后我试着输入内容:
诶?😦第一行输入的字上移了。
碰到问题当然先百度一下,没有结果。然后又必应一下,还是没有。
🙁要不就找个现成的项目看看它是怎么写的。然后从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),
),
效果和不写这个参数是一样的。如果我们传入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)
,我们来看看是啥效果:
我们可以看到,光标瞬间移到最前面。我们修改一下数值看看:
TextSelection.collapsed(offset: 10)
通过上面的实验我们可以发现,offset可以用来设置光标的位置(当offset=0
时和-1一样效果)。这还不算玩,我们试试删除这些文字会发生什么。
😦竟然从第10个字符开始,把后面的全都删除了。
TextSelection.collapsed
中还有一个可选参数affinity
,该参数可以传入两个不同的值:TextAffinity.upstream和TextAffinity.downstream(🤨下流???),其中 TextAffinity.downstream
是默认值,我们改成TextAffinity.upstream
一下看看是什么效果。。。试了一下,没有效果😦。。。如果有效果的话,会是如下样子:
该值用来设置,当字符串从offset处换行,光标应该显示在上一行还是下一行。
selection还可以传入TextSelection.fromPosition
方法,该方法需要传入一个TextPosition
对象的参数,该对象也有两个参数,和TextSelection.collapsed
一模一样,效果也一样。
现在来说说TextSelection
对象本身。
TextSelection
int baseOffset
:开始的位置int extentOffset
:结束的位置TextAffinity affinity
:光标的位置bool isDirectional
:是否消除了其基础和范围的歧义(不懂可以直接忽略)
该对象可以用来设置文本的选择范围:
selection: const TextSelection(
extentOffset: 5,
baseOffset: 12,
),
其实,TextSelection.fromPosition
是把TextSelection
对象的 extentOffset 和 baseOffset赋值给了同一个数,而TextSelection.collapsed
又是TextSelection.fromPosition
的简化版。
composing
该值传入一个TextRange对象,该对象有两个属性:
int start
:开始的位置int end
:结束的位置
我们来试试有什么效果:
composing: const TextRange(start: 8, end: 16),
我们设定的范围会有一条下划线。
composing的默认值为TextRange.empty
,相当于把start和end的值设置成-1,而TextRange.collapsed
方法是把start和end设置成相同的数值,所以显示效果回合TextRange.empty
一样。