如何汇总所有聊天的未读消息数并在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
相关产品推荐
相关产品推荐

