Flutter编辑页TextFormField点击后键盘弹出即关闭问题求助
Flutter编辑个人资料页面键盘弹出后立即关闭/刷新问题
在Flutter项目的编辑个人资料页面中,点击TextFormField后,键盘会瞬间弹出随即关闭/刷新。已尝试以下解决方案但均无效:
- 移除MediaQuery
- 修改AndroidManifest.xml中的adjustResize属性
- 移除Form的GlobalKey
页面代码
import 'package:abroad/models/user_model.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:line_awesome_flutter/line_awesome_flutter.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../../../../constants/sizes.dart'; import '../../../../constants/text_strings.dart'; import '../../controllers/profile_controller.dart'; class UpdateProfileScreen extends StatefulWidget { const UpdateProfileScreen({Key? key}) : super(key: key); @override State<UpdateProfileScreen> createState() => _UpdateProfileScreenState(); } class _UpdateProfileScreenState extends State<UpdateProfileScreen> { static final _formKey = GlobalKey<FormState>(); @override Widget build(BuildContext context) { final controller = Get.put(ProfileController()); return Scaffold( extendBodyBehindAppBar: true, appBar: AppBar( backgroundColor: Colors.transparent, elevation: 0, centerTitle: true, leading: IconButton( onPressed: () => Get.back(), icon: const Icon(LineAwesomeIcons.angle_left)), title: Text( tEditProfile, style: GoogleFonts.montserrat( fontWeight: FontWeight.bold, ), ), ), body: SingleChildScrollView( child: Container( width: double.infinity, height: MediaQuery.of(context).size.height, padding: const EdgeInsets.fromLTRB( tDefaultSize, tDefaultSize + 75, tDefaultSize, tDefaultSize), decoration: const BoxDecoration( image: DecorationImage( image: AssetImage( "assets/images/profile_images/profile_screen_background.png"), fit: BoxFit.cover, ), ), child: FutureBuilder( future: controller.getUserData(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { if (snapshot.hasData) { UserModel user = snapshot.data as UserModel; //controllers final id = TextEditingController(text: user.id); final email = TextEditingController(text: user.email); final password = TextEditingController(text: user.password); final fullName = TextEditingController(text: user.fullName); final phoneNo = TextEditingController(text: user.phoneNo); return Column( children: [ Stack( children: [ SizedBox( width: 120.w, height: 120.h, child: ClipRRect( borderRadius: BorderRadius.circular(100), child: const Image( image: AssetImage( "assets/images/profile_images/profile.png", ), ), ), ), Positioned( bottom: 0, right: 0, child: Container( width: 35.w, height: 35.h, decoration: BoxDecoration( borderRadius: BorderRadius.circular(100), color: Colors.blue), child: const Icon( LineAwesomeIcons.camera, color: Colors.black, size: 20, ), ), ), ], ), SizedBox(height: 25.h), Form( key: _formKey, child: Column( children: [ TextFormField( controller: fullName, style: const TextStyle( color: Colors.white, ), decoration: const InputDecoration( label: Text(tFullName), prefixIcon: Icon(Icons.person_outline_rounded)), ), SizedBox(height: tFormHeight - 10.h), TextFormField( controller: email, style: const TextStyle( color: Colors.white, ), decoration: const InputDecoration( label: Text(tEmail), prefixIcon: Icon(Icons.email_outlined)), ), SizedBox(height: tFormHeight - 10.h), TextFormField( controller: phoneNo, style: const TextStyle( color: Colors.white, ), decoration: const InputDecoration( label: Text(tPhoneNo), prefixIcon: Icon(Icons.numbers)), ), SizedBox(height: tFormHeight - 10.h), TextFormField( controller: password, obscureText: true, enableSuggestions: false, autocorrect: false, style: const TextStyle( color: Colors.white, ), decoration: const InputDecoration( label: Text(tPassword), prefixIcon: Icon(Icons.fingerprint)), ), const SizedBox(height: tFormHeight), SizedBox( width: 200.w, child: ElevatedButton( onPressed: () async { final userData = UserModel( id: id.text, email: email.text.trim(), password: password.text.trim(), fullName: fullName.text.trim(), phoneNo: phoneNo.text.trim(), ); await controller.updateRecord(userData); }, style: ElevatedButton.styleFrom( minimumSize: const Size(175, 50), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30), side: const BorderSide( color: Colors.white, width: 2), ), backgroundColor: Colors.transparent, ), child: const Text(tEditProfile, style: TextStyle(color: Colors.white)), ), ), ], )) ], ); } else if (snapshot.hasError) { return Center(child: Text(snapshot.error.toString())); } else { return const Center(child: Text('Something went wrong')); } } else { return Center(child: CircularProgressIndicator()); } }, ), ), ), ); } }
问题根源
你将TextEditingController的创建放在了FutureBuilder的builder方法内部,每次Widget重建(比如键盘弹出触发布局变化)时,都会重新创建一批新的控制器,导致原来的控制器被销毁,TextFormField失去焦点,键盘随即关闭。
修复方案
将所有TextEditingController移到State类的成员变量中,在initState或Future完成后初始化,避免每次build重建:
修改后的代码
import 'package:abroad/models/user_model.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:line_awesome_flutter/line_awesome_flutter.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../../../../constants/sizes.dart'; import '../../../../constants/text_strings.dart'; import '../../controllers/profile_controller.dart'; class UpdateProfileScreen extends StatefulWidget { const UpdateProfileScreen({Key? key}) : super(key: key); @override State<UpdateProfileScreen> createState() => _UpdateProfileScreenState(); } class _UpdateProfileScreenState extends State<UpdateProfileScreen> { static final _formKey = GlobalKey<FormState>(); // 声明控制器为State成员变量 late TextEditingController id; late TextEditingController email; late TextEditingController password; late TextEditingController fullName; late TextEditingController phoneNo; final controller = Get.put(ProfileController()); @override void initState() { super.initState(); // 初始化用户数据与控制器 _initUserData(); } void _initUserData() async { UserModel user = await controller.getUserData(); setState(() { id = TextEditingController(text: user.id); email = TextEditingController(text: user.email); password = TextEditingController(text: user.password); fullName = TextEditingController(text: user.fullName); phoneNo = TextEditingController(text: user.phoneNo); }); } @override void dispose() { // 销毁控制器,避免内存泄漏 id.dispose(); email.dispose(); password.dispose(); fullName.dispose(); phoneNo.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( extendBodyBehindAppBar: true, appBar: AppBar( backgroundColor: Colors.transparent, elevation: 0, centerTitle: true, leading: IconButton( onPressed: () => Get.back(), icon: const Icon(LineAwesomeIcons.angle_left)), title: Text( tEditProfile, style: GoogleFonts.montserrat( fontWeight: FontWeight.bold, ), ), ), body: SingleChildScrollView( child: Container( width: double.infinity, height: MediaQuery.of(context).size.height, padding: const EdgeInsets.fromLTRB( tDefaultSize, tDefaultSize + 75, tDefaultSize, tDefaultSize), decoration: const BoxDecoration( image: DecorationImage( image: AssetImage( "assets/images/profile_images/profile_screen_background.png"), fit: BoxFit.cover, ), ), child: FutureBuilder( future: controller.getUserData(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { if (snapshot.hasData) { return Column( children: [ Stack( children: [ SizedBox( width: 120.w, height: 120.h, child: ClipRRect( borderRadius: BorderRadius.circular(100), child: const Image( image: AssetImage( "assets/images/profile_images/profile.png", ), ), ), ), Positioned( bottom: 0, right: 0, child: Container( width: 35.w, height: 35.h, decoration: BoxDecoration( borderRadius: BorderRadius.circular(100), color: Colors.blue), child: const Icon( LineAwesomeIcons.camera, color: Colors.black, size: 20, ), ), ), ], ), SizedBox(height: 25.h), Form( key: _formKey, child: Column( children: [ TextFormField( controller: fullName, style: const TextStyle( color: Colors.white, ), decoration: const InputDecoration( label: Text(tFullName), prefixIcon: Icon(Icons.person_outline_rounded)), ), SizedBox(height: tFormHeight - 10.h), TextFormField( controller: email, style: const TextStyle( color: Colors.white, ), decoration: const InputDecoration( label: Text(tEmail), prefixIcon: Icon(Icons.email_outlined)), ), SizedBox(height: tFormHeight - 10.h), TextFormField( controller: phoneNo, style: const TextStyle( color: Colors.white, ), decoration: const InputDecoration( label: Text(tPhoneNo), prefixIcon: Icon(Icons.numbers)), ), SizedBox(height: tFormHeight - 10.h), TextFormField( controller: password, obscureText: true, enableSuggestions: false, autocorrect: false, style: const TextStyle( color: Colors.white, ), decoration: const InputDecoration( label: Text(tPassword), prefixIcon: Icon(Icons.fingerprint)), ), const SizedBox(height: tFormHeight), SizedBox( width: 200.w, child: ElevatedButton( onPressed: () async { final userData = UserModel( id: id.text, email: email.text.trim(), password: password.text.trim(), fullName: fullName.text.trim(), phoneNo: phoneNo.text.trim(), ); await controller.updateRecord(userData); }, style: ElevatedButton.styleFrom( minimumSize: const Size(175, 50), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30), side: const BorderSide( color: Colors.white, width: 2), ), backgroundColor: Colors.transparent, ), child: const Text(tEditProfile, style: TextStyle(color: Colors.white)), ), ), ], )) ], ); } else if (snapshot.hasError) { return Center(child: Text(snapshot.error.toString())); } else { return const Center(child: Text('Something went wrong')); } } else { return Center(child: CircularProgressIndicator()); } }, ), ), ), ); } }
额外说明
- 在
dispose方法中销毁所有控制器,防止内存泄漏。 - 将
ProfileController实例放在State成员变量中,避免每次build重复调用Get.put创建实例。
内容的提问来源于stack exchange,提问作者Ibrahim Essam
相关产品推荐
相关产品推荐

