Flutter中showDialog无法弹出,无法更新Firestore用户资料
问题修复:Flutter用户资料编辑对话框无响应及Firestore更新实现
问题分析
- 无状态组件状态异常:
ProfilePage是StatelessWidget,但类中声明了selectedFileName、file等可变字段,且editField方法内的状态逻辑不符合无状态组件设计规范,会导致UI更新异常,对话框无法正常触发。 - 空指针风险:未对
currentUser做空判断,若用户未登录会直接引发崩溃。 - 对话框返回值处理不当:依赖外部变量
newValue接收输入内容,未直接利用showDialog的返回值,易出现数据同步问题。
修复步骤
- 将
ProfilePage改为StatefulWidget,统一管理组件内可变状态。 - 优化
editField方法,直接获取showDialog的返回值,简化逻辑。 - 增加
currentUser空判断,提升代码健壮性。 - 确保
UserInfoTile的onPressed回调正确绑定(若为自定义组件,需确认内部正确触发该回调)。
完整修复代码
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:image_picker/image_picker.dart'; import 'package:jomasak/views/screens/auth/welcome_page.dart'; import 'package:jomasak/views/utils/AppColor.dart'; import 'package:jomasak/views/widgets/user_info_tile.dart'; class ProfilePage extends StatefulWidget { const ProfilePage({Key? key}) : super(key: key); @override State<ProfilePage> createState() => _ProfilePageState(); } class _ProfilePageState extends State<ProfilePage> { User? get currentUser => FirebaseAuth.instance.currentUser; final userCollection = FirebaseFirestore.instance.collection('users'); String defaultImageURL = 'https://pixabay.com/get/g066bc81cdaafbd755a118bbffa3223a1bd405dc2b5e972b603bf51a2bac5ad9c328e204c50642e1cb2b8c5574e9f5126aa31ca57206186d4ac7e15b8403ff8a61ae4a75edb280f4e1a9b572606dc6cf0_1280.png'; String selectedFileName = ''; XFile? file; Future<void> editField(String field) async { final TextEditingController textEditingController = TextEditingController(); final newValue = await showDialog<String>( context: context, builder: (context) { return Dialog( backgroundColor: Colors.grey[900], child: Column( mainAxisSize: MainAxisSize.min, children: [ Padding( padding: const EdgeInsets.all(16.0), child: Text( "Edit $field", style: const TextStyle(color: Colors.white), ), ), Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: TextField( controller: textEditingController, autofocus: true, style: const TextStyle(color: Colors.white), decoration: InputDecoration( hintText: "Enter new $field", hintStyle: const TextStyle(color: Colors.grey), ), ), ), ButtonBar( children: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text( 'Cancel', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, ), ), ), TextButton( onPressed: () { Navigator.of(context).pop(textEditingController.text.trim()); }, child: const Text( 'Save', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, ), ), ), ], ), ], ), ); }, ); // 更新Firestore数据 if (newValue != null && newValue.isNotEmpty && currentUser?.email != null) { await userCollection.doc(currentUser!.email).update({field: newValue}); } } @override Widget build(BuildContext context) { if (currentUser == null) { return const Scaffold( body: Center(child: Text('请先登录')), ); } return Scaffold( appBar: AppBar( brightness: Brightness.dark, backgroundColor: AppColor.primary, elevation: 0, centerTitle: true, title: const Text( 'My Profile', style: TextStyle( fontFamily: 'inter', fontWeight: FontWeight.w400, fontSize: 16, ), ), leading: IconButton( icon: const Icon(Icons.arrow_back_ios, color: Colors.white), onPressed: () => Navigator.of(context).pop(), ), actions: [ TextButton( onPressed: () async { await FirebaseAuth.instance.signOut(); print("Signed Out"); Navigator.of(context).pushAndRemoveUntil( MaterialPageRoute(builder: (context) => const WelcomePage()), (Route<dynamic> route) => false, ); }, child: const Icon( Icons.logout, color: Colors.white, size: 20, ), style: TextButton.styleFrom( primary: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(100), ), ), ), ], ), body: StreamBuilder<DocumentSnapshot>( stream: userCollection.doc(currentUser!.email).snapshots(), builder: (context, snapshot) { if (snapshot.hasData) { final userData = Map<String, dynamic>.from(snapshot.data!.data() ?? {}); return ListView( shrinkWrap: true, physics: const BouncingScrollPhysics(), children: [ // 头像区域 Container( color: AppColor.primary, padding: const EdgeInsets.symmetric(vertical: 24), child: GestureDetector( onTap: () => print('打开文件管理器选择图片'), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( width: 130, height: 130, margin: const EdgeInsets.only(bottom: 15), decoration: BoxDecoration( color: Colors.grey, borderRadius: BorderRadius.circular(100), image: const DecorationImage( image: AssetImage('assets/images/profile.jpeg'), fit: BoxFit.cover, ), ), ), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text( 'Change Profile Picture', style: TextStyle( fontFamily: 'inter', fontWeight: FontWeight.w600, color: Colors.white, ), ), const SizedBox(width: 8), SvgPicture.asset( 'assets/icons/camera.svg', color: Colors.white, ), ], ) ], ), ), ), // 用户信息区域 Container( margin: const EdgeInsets.only(top: 24), width: MediaQuery.of(context).size.width, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ UserInfoTile( margin: const EdgeInsets.only(bottom: 16), label: 'Email', value: userData['email'] ?? '', onPressed: () => editField('email'), ), UserInfoTile( margin: const EdgeInsets.only(bottom: 16), label: 'Full Name', value: userData['fullname'] ?? '', onPressed: () => editField('fullname'), ), UserInfoTile( margin: const EdgeInsets.only(bottom: 16), label: 'Username', value: userData['username'] ?? '', onPressed: () => editField('username'), ), UserInfoTile( margin: const EdgeInsets.only(bottom: 16), label: 'Bio', value: userData['bio'] ?? '', onPressed: () => editField('bio'), valueBackground: AppColor.secondary, ), ], ), ), ], ); } else if (snapshot.hasError) { return Center(child: Text('加载失败: ${snapshot.error}')); } return const Center(child: CircularProgressIndicator()); }, ), ); } }
额外说明
- 若
UserInfoTile自定义组件存在问题,需确保其内部通过InkWell或GestureDetector正确绑定onPressed回调。 - 头像修改功能可后续通过
ImagePicker实现图片选择,上传至Firebase Storage后更新Firestore中的头像URL。
内容的提问来源于stack exchange,提问作者Jennie Kim
相关产品推荐
相关产品推荐

