Flutter中TextFormField文本未变更时文本变更监听器多次触发的原因是什么
问题原因
TextEditingController的监听器默认监听的是控制器所有属性的变更,不止包含文本内容,还包含光标位置、文本选中范围、输入焦点状态、输入法合成状态等属性。点击输入框时会触发光标位置更新,点击输入框外区域时会触发焦点状态变更,二者都会触发监听器回调,这是Flutter的官方设计,并非Bug。
解决方案
方案1:自行过滤非文本变更的回调
在回调中缓存上一次的文本内容,仅当文本实际发生变化时执行业务逻辑,同时需要在页面销毁时主动移除监听器、销毁控制器避免内存泄漏,完整代码如下:
import 'dart:math'; import 'package:flutter/material.dart'; void main() { runApp(MaterialApp( home: SearchView(), )); } class SearchView extends StatefulWidget { @override State<SearchView> createState() => _SearchViewState(); } class _SearchViewState extends State<SearchView> { final textController = TextEditingController(); final rng = Random(); // 缓存上一次的文本内容 String _lastText = ''; @override void initState() { textController.addListener(_onTextChanged); super.initState(); } void _onTextChanged() { final currentText = textController.text; // 仅文本实际变更时执行业务逻辑 if (currentText != _lastText) { _lastText = currentText; print('text changed listener called ${rng.nextDouble()}'); } } @override void dispose() { // 销毁前移除监听器、销毁控制器 textController.removeListener(_onTextChanged); textController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Brand'), ), body: SingleChildScrollView( child: Column( children: [ TextFormField( controller: textController, ), ], ), ), ); } }
方案2:直接使用onChanged回调
TextFormField自带的onChanged回调仅会在文本内容实际变更时触发,不会响应光标、焦点等状态变化,更符合文本变更监听的需求,无需额外绑定控制器监听器,代码示例如下:
TextFormField( controller: textController, onChanged: (newText) { print('text changed: $newText ${rng.nextDouble()}'); }, )
内容的提问来源于stack exchange,提问作者rosh-dev851
相关产品推荐
相关产品推荐

