如何在Flutter中通过Firebase Firestore显示用户名与头像
问题背景
我已编写获取用户名和头像的代码,且成功获取到文档ID。终端输出如下:
Restarted application in 425ms. flutter: DocumentReference<Map<String, dynamic>>(UserData/yKorLkbVK5jIGlWIti95)
UI部分已开发完成,界面效果:
CloudFirestore数据结构:
代码文件
setting.dart
import 'dart:ffi'; import 'package:Meucci/FireAuth/getUserData.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; class Setting extends StatefulWidget { const Setting({Key? key}) : super(key: key); @override State<Setting> createState() => _SettingState(); } class _SettingState extends State<Setting> { final user = FirebaseAuth.instance.currentUser; List<String> documentID = []; Future getDocumentID() async { await FirebaseFirestore.instance.collection('UserData').get().then( (snapshot) => snapshot.docs.forEach((element) { print(element.reference); //documentID.add(element.reference.id); }), ); } @override void initState() { getDocumentID(); super.initState(); } @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: Center( child: Column( children: [ SizedBox(height: 50), Stack( alignment: Alignment.bottomRight, children: [ Container( height: 150, width: 150, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all(color: Colors.purpleAccent, width: 3)), ), InkWell( onTap: () {}, child: CircleAvatar( child: Icon(Icons.edit, color: Colors.white), backgroundColor: Colors.purpleAccent[100], ), ) ], ), SizedBox(height: 50), Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text('Signed In as: ' + user!.email!), Material( child: MaterialButton( onPressed: () { FirebaseAuth.instance.signOut(); }, color: Colors.purpleAccent[100], child: Text('Sign Out'), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20.0))), ) ], ), ], ), ), )); } }
getUserData.dart
import 'package:flutter/material.dart'; class getUserData extends StatelessWidget { final String docId; getUserData({required this.docId}); CollectionReference users = FirebaseFirestore.instance.collection('UserData'); @override Widget build(BuildContext context) { return FutureBuilder<DocumentSnapshot>( future: users.doc(docId).get(), builder: ((context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { Map<String, dynamic> data = snapshot.data!.data() as Map<String, dynamic>; return Text('${data['name']}'); } return Text('Loading..'); }), ); } }
技术问题及解决方案
1. 使用FutureBuilder展示用户名
首先要修正当前获取文档ID的逻辑(原方法遍历所有用户,应只获取当前登录用户的文档ID):
// 新增获取当前用户文档ID的方法 Future<String?> getCurrentUserDocId() async { final currentUser = FirebaseAuth.instance.currentUser; if (currentUser == null) return null; // 按邮箱匹配用户文档(如果文档用UID作为ID,直接return currentUser.uid即可) final snapshot = await FirebaseFirestore.instance .collection('UserData') .where('email', isEqualTo: currentUser.email) .get(); return snapshot.docs.isNotEmpty ? snapshot.docs.first.id : null; }
然后修改Setting组件的状态管理,结合FutureBuilder展示用户名:
class _SettingState extends State<Setting> { final user = FirebaseAuth.instance.currentUser; String? currentUserDocId; @override void initState() { super.initState(); _fetchDocId(); } Future<void> _fetchDocId() async { final id = await getCurrentUserDocId(); setState(() => currentUserDocId = id); } @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: Center( child: Column( children: [ SizedBox(height: 50), // 头像区域(保留原代码) Stack( alignment: Alignment.bottomRight, children: [ Container( height: 150, width: 150, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all(color: Colors.purpleAccent, width: 3)), ), InkWell( onTap: () {}, child: CircleAvatar( child: Icon(Icons.edit, color: Colors.white), backgroundColor: Colors.purpleAccent[100], ), ) ], ), SizedBox(height: 20), // 用户名展示 currentUserDocId != null ? getUserData(docId: currentUserDocId!) : Text('加载中...'), SizedBox(height: 30), // 原有的邮箱和退出按钮区域 Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text('Signed In as: ' + user!.email!), Material( child: MaterialButton( onPressed: () => FirebaseAuth.instance.signOut(), color: Colors.purpleAccent[100], child: Text('Sign Out'), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20.0))), ) ], ), ], ), ), ), ); } }
2. 通过CloudFirestore的头像URL展示头像+用户名
先修改getUserData组件,使其能同时返回用户名和头像URL,或者直接在Setting组件中用FutureBuilder获取完整用户数据:
// 新增获取完整用户数据的工具函数 Future<Map<String, dynamic>?> fetchFullUserData(String docId) async { final snapshot = await FirebaseFirestore.instance.collection('UserData').doc(docId).get(); return snapshot.exists ? snapshot.data() as Map<String, dynamic> : null; }
然后重构Setting组件的build方法,整合头像和用户名展示:
@override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: Center( child: FutureBuilder<Map<String, dynamic>?>( future: currentUserDocId != null ? fetchFullUserData(currentUserDocId!) : null, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return CircularProgressIndicator(); } if (snapshot.hasError || snapshot.data == null) { return Text('加载用户信息失败'); } final userData = snapshot.data!; final userName = userData['name'] ?? '未设置用户名'; final avatarUrl = userData['avatar'] as String?; return Column( children: [ SizedBox(height: 50), // 带头像的圆形容器 Stack( alignment: Alignment.bottomRight, children: [ Container( height: 150, width: 150, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all(color: Colors.purpleAccent, width: 3)), child: avatarUrl != null ? ClipOval( child: Image.network( avatarUrl, fit: BoxFit.cover, width: 150, height: 150, errorBuilder: (_, __, ___) => Icon(Icons.person, size: 80), ), ) : Icon(Icons.person, size: 80), ), InkWell( onTap: () {}, child: CircleAvatar( child: Icon(Icons.edit, color: Colors.white), backgroundColor: Colors.purpleAccent[100], ), ) ], ), SizedBox(height: 20), // 头像下方的用户名 Text( userName, style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), SizedBox(height: 30), // 原有的邮箱和退出按钮区域 Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text('Signed In as: ' + user!.email!), Material( child: MaterialButton( onPressed: () => FirebaseAuth.instance.signOut(), color: Colors.purpleAccent[100], child: Text('Sign Out'), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20.0))), ) ], ), ], ); }, ), ), ), ); }
内容的提问来源于stack exchange,提问作者Zephys
相关产品推荐
相关产品推荐

