Flutter修改名称后再次编辑文本框内容自动回退问题求助
问题描述
在Flutter应用中实现了用户名修改功能,名称在页面加载前从SharedPreferences获取。首次修改名称功能正常,但再次打开编辑对话框时,文本框内容会自动回退到旧名称。
问题截图
- 修改前:

- 修改时:

- 回退至旧名称:

相关代码
class ProfileInfo extends StatefulWidget { String? name; String? email; ProfileInfo({widget.name, widget.email}); @override _ProfileInfoState createState() => _ProfileInfoState(); } class _ProfileInfoState extends State<ProfileInfo> { var nameController = TextEditingController(); void updateName(String newName) async { SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setString('name', newName); setState(() { nameController.text = newName; widget.name = newName; }); } void _showEditNameDialog(BuildContext context) { // Set the nameController.text to the current name nameController.text = widget.name ?? ''; showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text('Edit Name'), content: TextField( controller: nameController, decoration: InputDecoration(hintText: 'Enter your name'), ), actions: <Widget>[ TextButton( onPressed: () { Navigator.of(context).pop(); }, child: Text('Cancel'), ), ElevatedButton( onPressed: () { // Save the edited name if needed updateName(nameController.text); Navigator.of(context).pop(); }, child: Text('Save'), ), ], ); }, ); } void redirtohome() async { var t = await getQuote(); Navigator.of(context).pushReplacement( MaterialPageRoute( fullscreenDialog: true, builder: (context) => home_page(quotes: t), ), ); } @override Widget build(BuildContext context) { Size size = MediaQuery.of(context).size; return Column( children: [ SizedBox( width: size.width * .9, child: Row( children: [ InkWell( onTap: Navigator.of(context).pop, child: Image.asset( "assets/images/whitebackarrow.png", width: size.width * .05, ), ), SizedBox(width: 10), Text( 'Edit Profile', style: TextStyle(color: Colors.white, fontSize: 20), ), Spacer(), SizedBox( width: size.width * .3, height: size.height * .065, child: ElevatedButton( style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), backgroundColor: Colors.transparent, shadowColor: Colors.transparent, ), onPressed: () { redirtohome(); }, child: Text( 'JustLift', style: TextStyle( color: Colors.white, fontSize: 16.0, fontWeight: FontWeight.bold, ), ), ), ), ], )), SizedBox(height: 10), SizedBox(height: 10), Container( height: size.height * 0.3, width: size.width * .9, child: Stack( alignment: Alignment.center, children: <Widget>[ Icon( Icons.circle, color: Color(0xff11b779), size: size.height * 0.3, ), Text( widget.name!.length >= 2 ? widget.name!.substring(0, 2).toUpperCase() : widget.name!, style: TextStyle( fontSize: size.height * 0.13, color: Colors.white, fontWeight: FontWeight.bold), ), ], ), ), SizedBox(height: 10), Container( width: size.width * .9, height: 30, color: Colors.grey.withOpacity(.14), padding: EdgeInsets.only(top: 4, left: 10), child: Text( 'NAME', style: TextStyle( fontSize: 18, color: Colors.grey.withOpacity(.8), fontWeight: FontWeight.bold, ), ), ), Container( width: size.width * .9, child: TextButton( onPressed: () { _showEditNameDialog(context); }, child: Row(children: [ Text( widget.name!, style: const TextStyle( color: Color(0xFFCECECE), fontSize: 18, fontWeight: FontWeight.bold, ), ), Spacer(), Icon(Icons.edit, color: Color(0xFFCECECE)), ]))), Container( width: size.width * .9, height: 30, color: Colors.grey.withOpacity(.14), padding: EdgeInsets.only(top: 4, left: 10), child: Text( 'EMAIL', style: TextStyle( fontSize: 18, color: Colors.grey.withOpacity(.8), fontWeight: FontWeight.bold, ), ), ), Container( width: size.width * .9, padding: EdgeInsets.all(10), child: Text( widget.email!, style: const TextStyle( color: Color(0xFFCECECE), fontSize: 18, fontWeight: FontWeight.bold, ), ), ) ], ); } } class EditProfilePage extends StatefulWidget { @override _EditProfilePageState createState() => _EditProfilePageState(); } class _EditProfilePageState extends State<EditProfilePage> { String? name = ''; String? email = ''; @override void initState() { super.initState(); getInfo(); } Future<void> getInfo() async { SharedPreferences prefs = await SharedPreferences.getInstance(); setState(() { name = prefs.getString('name'); email = prefs.getString('email'); }); } @override Widget build(BuildContext context) { if (name == null || email == null) { return Center( child: SizedBox( height: 50.0, // or another size width: 50.0, child: CircularProgressIndicator(), ), ); } else { return buildPage(context); } } @override Widget buildPage(BuildContext context) { Size size = MediaQuery.of(context).size; double height = MediaQuery.of(context).viewPadding.top; return Scaffold( resizeToAvoidBottomInset: false, backgroundColor: AppColors('Default').main2, body: Column(children: [ SizedBox(height: MediaQuery.of(context).padding.top + 10), Expanded( child: ProfileInfo(name: name, email: email), ), Align(alignment: Alignment.bottomCenter, child: Footer(tab: 'More')) ])); } }
问题原因
- 直接修改
widget.name违反了Flutter的状态管理原则:StatefulWidget的属性应该是不可变的,修改后无法触发父组件的状态更新。 - EditProfilePage中的
name状态没有同步更新,导致ProfileInfo接收的始终是旧值,再次打开对话框时文本框被设置回旧名称。
解决方案
修改ProfileInfo组件
添加回调函数通知父组件更新状态,同步控制器文本与最新名称:
class ProfileInfo extends StatefulWidget { final String? name; final String? email; final Function(String) onNameUpdated; // 添加回调 const ProfileInfo({ super.key, required this.name, required this.email, required this.onNameUpdated, }); @override _ProfileInfoState createState() => _ProfileInfoState(); } class _ProfileInfoState extends State<ProfileInfo> { late TextEditingController nameController; @override void initState() { super.initState(); nameController = TextEditingController(text: widget.name ?? ''); } @override void didUpdateWidget(covariant ProfileInfo oldWidget) { super.didUpdateWidget(oldWidget); // 父组件name更新时同步控制器文本 if (oldWidget.name != widget.name) { nameController.text = widget.name ?? ''; } } void updateName(String newName) async { SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.setString('name', newName); // 通知父组件更新状态 widget.onNameUpdated(newName); } // _showEditNameDialog及其他代码保持不变... }
修改EditProfilePage组件
接收回调更新自身的name状态,确保子组件获取最新值:
class EditProfilePage extends StatefulWidget { @override _EditProfilePageState createState() => _EditProfilePageState(); } class _EditProfilePageState extends State<EditProfilePage> { String? name = ''; String? email = ''; @override void initState() { super.initState(); getInfo(); } Future<void> getInfo() async { SharedPreferences prefs = await SharedPreferences.getInstance(); setState(() { name = prefs.getString('name'); email = prefs.getString('email'); }); } @override Widget build(BuildContext context) { if (name == null || email == null) { return const Center( child: SizedBox( height: 50.0, width: 50.0, child: CircularProgressIndicator(), ), ); } else { return buildPage(context); } } Widget buildPage(BuildContext context) { Size size = MediaQuery.of(context).size; return Scaffold( resizeToAvoidBottomInset: false, backgroundColor: AppColors('Default').main2, body: Column(children: [ SizedBox(height: MediaQuery.of(context).padding.top + 10), Expanded( child: ProfileInfo( name: name, email: email, onNameUpdated: (newName) { // 更新自身name状态 setState(() { name = newName; }); }, ), ), const Align(alignment: Alignment.bottomCenter, child: Footer(tab: 'More')) ]), ); } }
修复说明
- 通过回调实现父子组件状态同步,符合Flutter单向数据流原则。
- 利用
didUpdateWidget方法确保控制器文本始终与最新名称一致。 - 不再直接修改widget属性,避免状态不一致问题。
内容的提问来源于stack exchange,提问作者Cidiko Andorem
相关产品推荐
相关产品推荐

