Flutter中TextField重新聚焦时光标跳到已有文本起始位置是什么原因?
Flutter TextField重新获取焦点时光标跳转至开头问题解决方案
问题根因
你在build方法内直接创建TextEditingController实例,且仅为其赋值了text属性,没有配置光标位置信息:
- 每次页面触发重建(TextField失去焦点、UI更新都会触发build执行),旧的controller会被销毁,新的controller实例被创建
- 新创建的
TextEditingController如果只赋值text,默认的光标选择态selection是TextSelection.collapsed(offset: 0),也就是文本起始位置 - 当TextField重新获得焦点时,会直接读取controller当前的selection值,光标就定位到了开头
切记不要在build方法中重复创建TextEditingController实例,这会导致所有编辑状态、光标位置完全丢失
解决方案
方案1:将Controller放到State中生命周期管理(最推荐)
把当前的StatelessWidget改成StatefulWidget,将TextEditingController作为State的成员变量,在initState中初始化,dispose中销毁,避免每次build重复创建:
class Mypage extends StatefulWidget { const Mypage({Key? key}) : super(key: key); @override State<Mypage> createState() => _MypageState(); } class _MypageState extends State<Mypage> { // 声明Controller作为成员变量 late final TextEditingController _controller; @override void initState() { super.initState(); // 初始化时赋值文本 _controller = TextEditingController(text: 'Existing Text Here'); } @override void dispose() { // 销毁Controller防止内存泄漏 _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ TextField( // 直接使用已有的controller实例 controller: _controller, ), TextButton( onPressed: () { FocusScope.of(context).unfocus(); }, child: const Text('Unfocus')) ], ), ), ); } }
方案2:动态赋值文本时同步保留selection状态
如果业务需要每次build都要更新TextField的文本,赋值时不要直接改text属性,要通过value同时保留原来的光标位置:
// 错误写法,会丢失selection // controller.text = '新的文本'; // 正确写法,保留原光标位置,如果光标超过新文本长度就自动放到末尾 controller.value = controller.value.copyWith( text: '新的文本', selection: controller.value.selection.baseOffset > '新的文本'.length ? TextSelection.collapsed(offset: '新的文本'.length) : controller.value.selection, );
内容的提问来源于stack exchange,提问作者satoru_02
相关产品推荐
相关产品推荐

