Flutter中点击键盘完成按钮后TextField的onChanged属性失效
问题分析
直接点击添加按钮能正常添加任务,但输入文本后点击键盘完成按钮,控制台输出I/TextInputPlugin( 6522): Composing region changed by the framework. Restarting the input method.,此时再点击添加按钮会添加空内容。
原代码
class AddTaskScreen extends StatelessWidget { const AddTaskScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { String newTask = ''; return Container( color: const Color.fromARGB(255, 117, 117, 117), child: Container( decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0), ), ), child: Container( padding: const EdgeInsets.all(30.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( 'Add Task', textAlign: TextAlign.center, style: TextStyle( color: Colors.amber[900], fontSize: 30.0, ), ), TextField( onChanged: (value) { newTask = value; }, autofocus: true, textCapitalization: TextCapitalization.sentences, textAlign: TextAlign.center, decoration: const InputDecoration( focusedBorder: UnderlineInputBorder( borderSide: BorderSide(color: Color.fromRGBO(255, 111, 0, 1)), ), ), ), const SizedBox(height: 30.0), TextButton( onPressed: () { Provider.of<TaskData>(context, listen: false).addTask(newTask); Navigator.pop(context); }, style: TextButton.styleFrom( backgroundColor: Colors.amber[900], ), child: const Text( 'Add', style: TextStyle(color: Colors.white), ), ), ], ), ), ), ); } }
问题根源
newTask变量定义在build方法内部,而StatelessWidget的build方法会在widget重建时重新执行。当点击键盘完成按钮时,会触发widget重建,此时newTask会被重新初始化为空字符串,导致后续点击添加按钮时传入空值。
你尝试用TextEditingController但没解决,大概率是因为没有正确管理controller的生命周期,或者在重建时重新创建了controller,导致无法获取最新输入内容。
解决方案
将StatelessWidget改为StatefulWidget,把状态变量放到state类中;或者正确使用TextEditingController并在state中持有它,两种方案任选其一即可。
方案一:改为StatefulWidget
class AddTaskScreen extends StatefulWidget { const AddTaskScreen({Key? key}) : super(key: key); @override State<AddTaskScreen> createState() => _AddTaskScreenState(); } class _AddTaskScreenState extends State<AddTaskScreen> { String newTask = ''; @override Widget build(BuildContext context) { return Container( color: const Color.fromARGB(255, 117, 117, 117), child: Container( decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0), ), ), child: Container( padding: const EdgeInsets.all(30.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( 'Add Task', textAlign: TextAlign.center, style: TextStyle( color: Colors.amber[900], fontSize: 30.0, ), ), TextField( onChanged: (value) { setState(() { newTask = value; }); }, autofocus: true, textCapitalization: TextCapitalization.sentences, textAlign: TextAlign.center, decoration: const InputDecoration( focusedBorder: UnderlineInputBorder( borderSide: BorderSide(color: Color.fromRGBO(255, 111, 0, 1)), ), ), ), const SizedBox(height: 30.0), TextButton( onPressed: () { Provider.of<TaskData>(context, listen: false).addTask(newTask); Navigator.pop(context); }, style: TextButton.styleFrom( backgroundColor: Colors.amber[900], ), child: const Text( 'Add', style: TextStyle(color: Colors.white), ), ), ], ), ), ), ); } }
方案二:使用TextEditingController
class AddTaskScreen extends StatefulWidget { const AddTaskScreen({Key? key}) : super(key: key); @override State<AddTaskScreen> createState() => _AddTaskScreenState(); } class _AddTaskScreenState extends State<AddTaskScreen> { final TextEditingController _taskController = TextEditingController(); @override void dispose() { _taskController.dispose(); // 销毁controller避免内存泄漏 super.dispose(); } @override Widget build(BuildContext context) { return Container( color: const Color.fromARGB(255, 117, 117, 117), child: Container( decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0), ), ), child: Container( padding: const EdgeInsets.all(30.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( 'Add Task', textAlign: TextAlign.center, style: TextStyle( color: Colors.amber[900], fontSize: 30.0, ), ), TextField( controller: _taskController, autofocus: true, textCapitalization: TextCapitalization.sentences, textAlign: TextAlign.center, decoration: const InputDecoration( focusedBorder: UnderlineInputBorder( borderSide: BorderSide(color: Color.fromRGBO(255, 111, 0, 1)), ), ), ), const SizedBox(height: 30.0), TextButton( onPressed: () { Provider.of<TaskData>(context, listen: false).addTask(_taskController.text.trim()); Navigator.pop(context); }, style: TextButton.styleFrom( backgroundColor: Colors.amber[900], ), child: const Text( 'Add', style: TextStyle(color: Colors.white), ), ), ], ), ), ), ); } }
关键说明
- 把状态变量(
newTask或TextEditingController)放到State类中,widget重建时不会重新初始化这些变量,能保留输入内容。 - 使用
TextEditingController时必须在dispose方法中销毁它,避免内存泄漏。 - 可以给输入内容加
trim(),过滤掉前后空格,避免添加空任务。
内容的提问来源于stack exchange,提问作者Sai Gruheeth
相关产品推荐
相关产品推荐

