为什么Flutter中TextFormField获得焦点时页面会自动重载?
问题根本原因
你当前将Users.doc(uid).get()这个Future直接写在了FutureBuilder的future属性中,每次调用setState触发页面重绘时,都会重新执行这个Future请求,导致FutureBuilder刷新重建,输入框的状态被重置,自然无法正常输入。你查到的把Future放到initState中预加载的思路是完全正确的。
具体实现步骤
- 在State类中定义一个Future类型的变量,用来缓存用户数据请求:
class _UpdateProfileState extends State<UpdateProfile> { final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); // 新增缓存请求的变量 late Future<DocumentSnapshot> _userFuture; late String _name; // 其余原有变量保留 }
- 在
initState生命周期方法中初始化这个Future,该方法只会在组件初始化时执行一次,不会跟随页面重绘重复触发:
@override void initState() { super.initState(); _userFuture = Users.doc(uid).get(); }
- 将
FutureBuilder的future参数替换为缓存好的_userFuture变量,同时在拿到数据时给_name赋初始值:
FutureBuilder<DocumentSnapshot>( // 替换为缓存的请求变量,不要直接写请求方法 future: _userFuture, builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) { if (snapshot.hasError) { return Text("Something went wrong"); } if (snapshot.hasData && !snapshot.data!.exists) { return Text("Document does not exist"); } if (snapshot.connectionState == ConnectionState.done) { // 给_name赋初始值 Map<String, dynamic> data = snapshot.data!.data() as Map<String, dynamic>; _name = data['displayName'].toString(); return displayUserInformation(context, snapshot); } else { return SizedBox(height: 400, child: Center(child: CircularProgressIndicator())); } }, ),
- 调整
TextFormField的initialValue取值,直接取_name即可:
TextFormField( onChanged: (value) => setState(() => _name = value.trim()), initialValue: _name, // 其余原有配置保持不变 cursorColor: DarkTurquoise, decoration: InputDecoration( labelText: 'Name', labelStyle: TextStyle( color: SeaTurquoise ), focusedBorder: UnderlineInputBorder( borderSide: BorderSide(color: SeaTurquoise, width: 2.0),), enabledBorder: UnderlineInputBorder( borderSide: BorderSide(color: DarkGrey), ), ), )
补充注意点
如果后续需要更灵活地控制输入内容,可以选择使用TextEditingController替代initialValue的写法,同样在initState中给控制器赋初始值即可,两种方案都可以解决输入重置的问题。
内容的提问来源于stack exchange,提问作者kernelrpc_mach_vm_protect
相关产品推荐
相关产品推荐

