You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中showDialog无法弹出,无法更新Firestore用户资料

问题修复:Flutter用户资料编辑对话框无响应及Firestore更新实现

问题分析

  1. 无状态组件状态异常:ProfilePage是StatelessWidget,但类中声明了selectedFileName、file等可变字段,且editField方法内的状态逻辑不符合无状态组件设计规范,会导致UI更新异常,对话框无法正常触发。
  2. 空指针风险:未对currentUser做空判断,若用户未登录会直接引发崩溃。
  3. 对话框返回值处理不当:依赖外部变量newValue接收输入内容,未直接利用showDialog的返回值,易出现数据同步问题。

修复步骤

  1. 将ProfilePage改为StatefulWidget,统一管理组件内可变状态。
  2. 优化editField方法,直接获取showDialog的返回值,简化逻辑。
  3. 增加currentUser空判断,提升代码健壮性。
  4. 确保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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 17:42:03