为何设置TextEditingController.text与.value会产生不同输出?
Flutter TextEditingController赋值text为何多触发一次监听?
最小可复现代码
class SomePage extends StatefulWidget { @override State<SomePage> createState() => _SomePageState(); } class _SomePageState extends State<SomePage> { final TextEditingController _controller = TextEditingController(); @override void initState() { super.initState(); _controller.addListener(() { final String currentText = _controller.text; print(currentText); if (currentText == 'foo') { _controller.text = 'bar'; // 1 // _controller.value = _controller.value.copyWith(text: 'bar'); // 2 } }); } @override Widget build(BuildContext context) => Material(child: TextField(controller: _controller)); }
两种选项的输出
- 使用选项1(
_controller.text = 'bar';)时,输出:
f fo foo bar bar
- 使用选项2(
_controller.value = _controller.value.copyWith(text: 'bar');)时,输出:
f fo foo bar
问题:为何使用选项1时会多打印一个bar?
原因解释
核心差异在于两种赋值方式对TextEditingValue的修改范围不同:
选项1的
textsetter实现:
调用_controller.text = 'bar'时,内部会生成全新的TextEditingValue对象,除了修改文本为bar,还会自动将光标(selection)移到文本末尾,同时清空「正在输入」的标记(composing范围)。一次赋值同时修改了文本、光标位置、输入状态三个属性。在监听回调处理
foo时,这次赋值先因文本变化触发一次监听(打印bar),紧接着又因光标位置和输入状态的变化再次触发监听,此时文本内容仍是bar,因此多打印一次。选项2的
value.copyWith实现:
调用_controller.value.copyWith(text: 'bar')时,仅修改TextEditingValue的文本属性,光标位置和输入状态保留输入foo时的原有值。因此只会因文本变化触发一次监听,不会产生额外回调。
内容的提问来源于stack exchange,提问作者iDecode
相关产品推荐
相关产品推荐

