Flutter-Firebase Firestore:如何通过用户ID获取并显示用户名
解决方案:替换用户ID为用户名显示
要实现用用户名替代用户ID展示,核心是通过user_id从Firestore的用户集合中异步获取对应的用户信息,以下是具体实现步骤:
1. 确认Firestore用户集合结构
假设你有一个名为users的集合,每个用户文档的ID就是user_id,文档中包含username字段(存储用户名)。如果还没有,需要先确保用户数据的存储结构符合这个逻辑。
2. 修改列表项的用户名展示部分
在FirestoreListView的itemBuilder中,将原来直接显示actu.user_id!的RichText替换为FutureBuilder,异步获取并展示用户名:
修改后的关键代码片段
// 替换原来的RichText部分 FutureBuilder<DocumentSnapshot>( future: FirebaseFirestore.instance.collection('users').doc(actu.user_id!).get(), builder: (context, userSnapshot) { if (userSnapshot.connectionState == ConnectionState.waiting) { // 加载中显示占位符 return Text( '加载中...', style: TextStyle( color: Colors.grey[900], fontSize: getProportionateScreenWidth(12), fontWeight: FontWeight.bold, letterSpacing: 1, ), ); } if (userSnapshot.hasError || !userSnapshot.hasData) { // 出错或无数据时显示原ID作为 fallback return Text( actu.user_id!, style: TextStyle( color: Colors.grey[900], fontSize: getProportionateScreenWidth(12), fontWeight: FontWeight.bold, letterSpacing: 1, ), ); } // 获取用户名并展示 String username = userSnapshot.data!['username'] ?? actu.user_id!; return RichText( text: TextSpan( text: username, style: TextStyle( color: Colors.grey[900], fontSize: getProportionateScreenWidth(12), fontWeight: FontWeight.bold, letterSpacing: 1, ), ), overflow: TextOverflow.ellipsis, ); }, )
3. 完整修改后的组件代码
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutterfire_ui/firestore.dart'; import 'package:flyzik/models/post_model.dart'; import 'package:flyzik/services/db_service.dart'; import 'package:lottie/lottie.dart'; import 'package:shimmer/shimmer.dart'; import 'package:timeago/timeago.dart' as timeago; import '../constants.dart'; import '../size_config.dart'; class ActualiteWidget extends StatefulWidget { ActualiteWidget({Key? key}) : super(key: key); @override State<ActualiteWidget> createState() => _ActualiteWidgetState(); } class _ActualiteWidgetState extends State<ActualiteWidget> { @override Widget build(BuildContext context) { timeago.setLocaleMessages('fr_short', timeago.FrShortMessages()); return FirestoreListView<PostModel>( shrinkWrap: true, loadingBuilder: (context) => dummyListActu(), errorBuilder: (context, error, stackTrace) => dummyCustomError(error, stackTrace), pageSize: 10, query: DBServices().getActualites, itemBuilder: (context, snapshot) { PostModel actu = snapshot.data(); return Container( margin: EdgeInsets.only(bottom: 10), padding: EdgeInsets.all(10), decoration: BoxDecoration( border: Border.all( color: Colors.black12, width: 1.5, ), borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Row( children: <Widget>[ Container( width: 40, height: 40, decoration: BoxDecoration( shape: BoxShape.circle, image: DecorationImage( image: NetworkImage(actu.imagePost!), fit: BoxFit.cover)), ), SizedBox( width: 10, ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ // 替换为FutureBuilder获取用户名 FutureBuilder<DocumentSnapshot>( future: FirebaseFirestore.instance.collection('users').doc(actu.user_id!).get(), builder: (context, userSnapshot) { if (userSnapshot.connectionState == ConnectionState.waiting) { return Text( '加载中...', style: TextStyle( color: Colors.grey[900], fontSize: getProportionateScreenWidth(12), fontWeight: FontWeight.bold, letterSpacing: 1, ), ); } if (userSnapshot.hasError || !userSnapshot.hasData) { return Text( actu.user_id!, style: TextStyle( color: Colors.grey[900], fontSize: getProportionateScreenWidth(12), fontWeight: FontWeight.bold, letterSpacing: 1, ), ); } String username = userSnapshot.data!['username'] ?? actu.user_id!; return RichText( text: TextSpan( text: username, style: TextStyle( color: Colors.grey[900], fontSize: getProportionateScreenWidth(12), fontWeight: FontWeight.bold, letterSpacing: 1, ), ), overflow: TextOverflow.ellipsis, ); }, ), SizedBox( height: 3, ), Text( "${timeago.format(DateTime.parse("${DateTime.fromMillisecondsSinceEpoch(actu.createAt!)}"), locale: 'fr_short')}", style: TextStyle( fontSize: getProportionateScreenWidth(10), color: Colors.grey), ), ], ) ], ), ], ), SizedBox( height: 5, ), RichText( text: TextSpan( text: actu.description!, style: TextStyle( fontSize: getProportionateScreenWidth(10), color: Colors.grey[800], height: 1.5, letterSpacing: .7), ), ), SizedBox( height: 5, ), Container( height: 200, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), image: DecorationImage( image: NetworkImage(actu.imagePost!), fit: BoxFit.cover, ), ), ), SizedBox( height: 5, ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ InkWell( onTap: (() => print("LIKE")), child: makeLikeButton(isActive: true), ), Padding( padding: EdgeInsets.only( right: 10, ), ), Row( children: <Widget>[ makeLike(), SizedBox( width: 5, ), Text( "2.5K", style: TextStyle( fontSize: getProportionateScreenWidth(10), color: Colors.grey[800]), ) ], ), ], ), ], ), ); }, ); } }
额外优化建议
- 可以在
DBServices中封装一个获取用户信息的方法,避免在UI层直接写Firestore调用,比如:
然后在FutureBuilder中调用Future<DocumentSnapshot> getUserById(String userId) { return FirebaseFirestore.instance.collection('users').doc(userId).get(); }DBServices().getUserById(actu.user_id!)。 - 如果列表数据较多,频繁的单个用户查询可能影响性能,可以考虑在发布帖子时将用户名冗余存储到
PostModel中,这样就不需要每次异步查询,直接从actu.username获取即可,这种方式更适合性能要求高的场景。
内容的提问来源于stack exchange,提问作者Ruben's A.
相关产品推荐
相关产品推荐

