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

如何汇总所有聊天的未读消息数并在BottomNavigationBar展示?

实现多个聊天会话未读消息总数求和

核心思路

要实现BottomNavigationBar的未读消息总数徽章,需要把每个聊天会话的未读数Stream合并,再实时计算所有数值的总和。具体分为三步:

  • 获取用户参与的所有聊天会话列表
  • 为每个会话生成对应的未读数Stream
  • 合并所有Stream并实时计算总和

具体实现步骤

1. 获取用户的聊天会话列表

首先需要一个能获取当前用户所有聊天会话的Stream,示例代码:

Stream<List<ChatEntity>> getUserChats(String uid) {
  return firebaseFirestore
      .collection('chats')
      .where('participantsid', arrayContains: uid)
      .snapshots()
      .map((snapshot) => snapshot.docs
          .map((doc) => ChatEntity.fromSnapshot(doc)) // 替换为你实际的ChatEntity转换方法
          .toList());
}

2. 合并所有会话的未读数Stream并求和

方法一:使用rxdart实现(简洁高效)

先在pubspec.yaml添加rxdart依赖,再用CombineLatestStream合并多个Stream:

import 'package:rxdart/rxdart.dart';

Stream<int> getTotalUnreadMessages(String uid) {
  return getUserChats(uid).switchMap((chats) {
    // 为每个聊天会话生成对应的未读数Stream
    final streams = chats.map((chat) => getNumMessageNotseen(chat)).toList();
    
    // 无聊天会话时直接返回0
    if (streams.isEmpty) return Stream.value(0);
    
    // 合并所有Stream,任一会话未读数更新时重新计算总和
    return CombineLatestStream.list(streams).map((unreadCounts) {
      return unreadCounts.reduce((total, count) => total + count);
    });
  });
}

方法二:原生Dart实现(无需第三方库)

如果不想依赖第三方库,可通过原生Stream组合实现:

Stream<int> getTotalUnreadMessages(String uid) {
  return getUserChats(uid).asyncExpand((chats) {
    if (chats.isEmpty) return Stream.value(0);
    
    // 初始化总和为0的Stream
    Stream<int> totalStream = Stream.value(0);
    
    for (var chat in chats) {
      final unreadStream = getNumMessageNotseen(chat);
      // 逐个合并每个会话的未读数到总和Stream
      totalStream = totalStream.combineLatest(unreadStream, (total, count) => total + count);
    }
    
    return totalStream;
  });
}

3. 优化原有单会话未读数计算代码

简化索引查找逻辑,优化空安全处理:

@override
Stream<int> getNumMessageNotseen(ChatEntity chat) {
  return firebaseFirestore
      .collection('chats')
      .doc(chat.cid)
      .collection('messages')
      .orderBy('createAt')
      .snapshots()
      .map((messages) {
    // 简化用户索引查找
    final userIdIndex = chat.participantsid?.indexOf(chat.uid) ?? -1;
    if (userIdIndex == -1) return 0;
    
    int num = 0;
    for (var doc in messages.docs) {
      final message = MessageModel.fromSnapshot(doc);
      // 空安全检查+未读判断
      if (message.senderid != chat.uid && message.isSeen != null && !message.isSeen![userIdIndex]) {
        num++;
      }
    }
    return num;
  });
}

4. 在BottomNavigationBar中使用

通过StreamBuilder监听总未读数,动态显示徽章:

// 假设聊天tab是第0项,在图标上叠加徽章
BottomNavigationBarItem(
  icon: Stack(
    children: [
      const Icon(Icons.chat),
      StreamBuilder<int>(
        stream: getTotalUnreadMessages(currentUserId), // 替换为当前用户ID
        initialData: 0,
        builder: (context, snapshot) {
          final totalUnread = snapshot.data ?? 0;
          if (totalUnread <= 0) return const SizedBox.shrink();
          
          return Positioned(
            right: 0,
            top: 0,
            child: Container(
              padding: const EdgeInsets.all(2),
              decoration: BoxDecoration(
                color: Colors.red,
                borderRadius: BorderRadius.circular(10),
              ),
              constraints: const BoxConstraints(
                minWidth: 20,
                minHeight: 20,
              ),
              child: Text(
                '$totalUnread',
                style: const TextStyle(
                  color: Colors.white,
                  fontSize: 12,
                ),
                textAlign: TextAlign.center,
              ),
            ),
          );
        },
      ),
    ],
  ),
  label: '聊天',
),

内容的提问来源于stack exchange,提问作者Mus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 03:33:24