Flutter评论框中TextFormField获得焦点时触发当前页面重载如何解决?
问题原因及修复方案
你遇到的键盘弹出后立刻消失、页面重载的核心原因是部件反复重建,具体问题点如下:
- 你把
reviewDisplayStream的初始化逻辑写在了外层StreamBuilder的builder方法内,只要页面触发任何重绘(比如键盘弹出导致页面尺寸变化),外层builder都会重新执行,生成一个全新的Firebase流实例,内层StreamBuilder检测到流变更就会重新加载数据、重建子部件,评论输入框失去焦点,键盘自然就被收回,看起来和页面重载一样。 - 你在
sendButtonMethod里错误给setState的回调加了async修饰,setState的回调必须是同步函数,异步逻辑写在里面会导致状态更新异常。 - 注意
formKey和commentController必须定义在当前State类的顶层,不能在build方法里初始化,不然每次重绘也会重置这两个实例,导致输入框状态丢失。
修复步骤
- 在当前页面的State类里定义两个流变量,在
initState里完成流的初始化,不要放在build方法里:
late Stream<QuerySnapshot> reviewStream; late Stream<QuerySnapshot> reviewDisplayStream; @override void initState() { super.initState(); // 初始化你的reviewStream,原来的流定义挪到这 reviewStream = // 你原来的reviewStream赋值逻辑 reviewDisplayStream = FirebaseFirestore.instance .collection("customer") .where("uid", isEqualTo: userId) .snapshots(); }
- 修正发送按钮的异步逻辑,把异步操作挪到setState外面:
sendButtonMethod: () async { if (formKey.currentState!.validate()) { print(commentController.text); Map<String, dynamic> value = { 'name': reviewDisplayList[0]['name'], 'pic': reviewDisplayList[0]['image'] != '' ? reviewDisplayList[0]['image'] : "https://firebasestorage.googleapis.com/v0/b/fir-prictice-81c0f.appspot.com/o/profile.png?alt=media&token=8fdf702b-8f5a-4a12-b46a-091758812a5d", 'message': commentController.text, 'date and time': date }; // 异步操作单独执行 await FirebaseFirestore.instance.collection("Review").add(value); // 操作完成后如果需要更新状态再调用setState setState(() {}); commentController.clear(); FocusScope.of(context).unfocus(); } else { print("Not validated"); } },
- 把原来外层builder里的
reviewDisplayStream定义删掉,直接用State里初始化好的流实例即可,避免每次build生成新流。
内容的提问来源于stack exchange,提问作者Suliman Khan
相关产品推荐
相关产品推荐

