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

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调用,比如:
    Future<DocumentSnapshot> getUserById(String userId) {
      return FirebaseFirestore.instance.collection('users').doc(userId).get();
    }
    
    然后在FutureBuilder中调用DBServices().getUserById(actu.user_id!)。
  • 如果列表数据较多,频繁的单个用户查询可能影响性能,可以考虑在发布帖子时将用户名冗余存储到PostModel中,这样就不需要每次异步查询,直接从actu.username获取即可,这种方式更适合性能要求高的场景。

内容的提问来源于stack exchange,提问作者Ruben's A.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 17:39:40