消息界面未读消息计数及输入状态展示功能技术咨询
需求实现方案:未读消息计数 + 正在输入状态
一、未读消息计数功能实现
1. 调整消息存储结构
当前你直接将消息文本存在键值对中,需要给每条消息新增已读状态字段,把单文本存储改成包含多字段的字典结构:
// 替换原发送逻辑里的updateChildValues代码 let messageData = [ "message": txtMsg.text!, "isRead": false, "senderUid": Auth.auth().currentUser!.uid ] as [String : Any] let targetUid = dict.object(forKey: "userid") as! String let currentUid = Auth.auth().currentUser!.uid let database = Database.database().reference() // 双向存储消息(保持双方聊天数据同步) database.child("Chats").child(targetUid).child(currentUid).updateChildValues([str : messageData]) database.child("Chats").child(currentUid).child(targetUid).updateChildValues([str : messageData])
2. 统计未读消息数量
在聊天界面监听消息变化,统计对方发送的、未标记为已读的消息数量:
func fetchUnreadCount() { let currentUid = Auth.auth().currentUser!.uid let targetUid = dict.object(forKey: "userid") as! String let chatRef = Database.database().reference().child("Chats").child(currentUid).child(targetUid) chatRef.observe(.value) { snapshot in var unreadCount = 0 for child in snapshot.children { guard let childSnapshot = child as? DataSnapshot, let messageDict = childSnapshot.value as? [String:Any], let isRead = messageDict["isRead"] as? Bool, let senderUid = messageDict["senderUid"] as? String, senderUid != currentUid else { continue } if !isRead { unreadCount += 1 } } // 更新界面计数(比如导航栏badge或界面内的数字标签) self.navigationItem.badgeValue = unreadCount > 0 ? "\(unreadCount)" : nil } }
3. 标记消息为已读
当用户进入聊天界面时,将对方发送的所有未读消息批量标记为已读:
func markMessagesAsRead() { let currentUid = Auth.auth().currentUser!.uid let targetUid = dict.object(forKey: "userid") as! String let chatRef = Database.database().reference().child("Chats").child(currentUid).child(targetUid) chatRef.observeSingleEvent(of: .value) { snapshot in var updates = [String:Any]() for child in snapshot.children { guard let childSnapshot = child as? DataSnapshot, let messageDict = childSnapshot.value as? [String:Any], let isRead = messageDict["isRead"] as? Bool, let senderUid = messageDict["senderUid"] as? String, senderUid != currentUid, !isRead else { continue } updates["\(childSnapshot.key)/isRead"] = true } if !updates.isEmpty { chatRef.updateChildValues(updates) // 同步更新对方侧的消息已读状态(保持数据一致性) Database.database().reference().child("Chats").child(targetUid).child(currentUid).updateChildValues(updates) } } }
在聊天界面的viewWillAppear方法中调用markMessagesAsRead()和fetchUnreadCount()。
二、「正在输入」状态实现
1. 监听本地输入状态并同步到数据库
新增TypingStatus节点存储用户输入状态,监听输入框的编辑事件:
func setupTypingListener() { txtMsg.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged) } @objc func textFieldDidChange() { let currentUid = Auth.auth().currentUser!.uid let targetUid = dict.object(forKey: "userid") as! String let typingRef = Database.database().reference().child("TypingStatus").child(targetUid).child(currentUid) if txtMsg.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == false { // 标记为正在输入,10秒后自动清除状态(避免用户停留在输入界面未发送的情况) typingRef.setValue(true) DispatchQueue.main.asyncAfter(deadline: .now() + 10) { typingRef.removeValue() } } else { // 停止输入,清除状态 typingRef.removeValue() } }
2. 监听对方输入状态并更新界面
在聊天界面监听对方的输入状态,动态显示/隐藏「正在输入」提示:
func listenForTypingStatus() { let currentUid = Auth.auth().currentUser!.uid let targetUid = dict.object(forKey: "userid") as! String let typingRef = Database.database().reference().child("TypingStatus").child(currentUid).child(targetUid) typingRef.observe(.value) { snapshot in if snapshot.exists() { // 显示「正在输入」提示(需提前在界面添加UILabel:typingStatusLabel) self.typingStatusLabel.isHidden = false self.typingStatusLabel.text = "正在输入" } else { self.typingStatusLabel.isHidden = true } } }
在viewDidLoad中调用setupTypingListener()和listenForTypingStatus(),同时记得在viewWillDisappear中移除所有数据库监听,避免内存泄漏:
override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) let currentUid = Auth.auth().currentUser!.uid let targetUid = dict.object(forKey: "userid") as! String Database.database().reference().child("Chats").child(currentUid).child(targetUid).removeAllObservers() Database.database().reference().child("TypingStatus").child(currentUid).child(targetUid).removeAllObservers() }
注意事项
- 需配置正确的Firebase数据库规则,确保用户仅能访问自己的聊天数据和输入状态节点;
- 处理用户退出登录或切换账号时的状态清理,避免无效数据残留。
内容的提问来源于stack exchange,提问作者Krunal Kathiriya
相关产品推荐
相关产品推荐

