“对方正在输入”状态 (Typing)
QXJIMSDK 基于 Go 核心层 internal/conversation_msg/entering.go 状态机,提供多端感知、自带节流与超时自动清理的“正在输入”状态能力。
1. 核心机制说明
- 发送端自动 10 秒节流 (
inputStatesSendTime = 10s):- 当用户在输入框连续打字、每敲击一个字符都调用
changeInputStates(conversationID: ..., focus: true)时,Go 核心层会通过内存缓存拦截 10 秒内的重复focus: true调用,每 10 秒最多发送一次信令包,业务层无需自己写防抖/节流定时器。 - 当用户清空输入框、点击发送按钮或退出聊天页时,调用
changeInputStates(conversationID: ..., focus: false),会立即通知对方停止展示“正在输入...”。
- 当用户在输入框连续打字、每敲击一个字符都调用
- 接收端 15 秒超时自动复位 (
inputStatesTimeout = 15s):- 即使发送端在打字中途直接杀进程或断网未发送
focus: false,接收端的 Go 核心层也会在超时后自动触发inputStatusEvents并回调isTyping = false(platformIDs = []),不会出现“正在输入...”永久卡死的情况。
- 即使发送端在打字中途直接杀进程或断网未发送
2. 数据模型 (IMInputStatusChangedData)
public struct IMInputStatusChangedData: Codable, Sendable, Equatable {
public var conversationID: String
public var userID: String
public var platformIDs: [Int32]?
/// 便捷布尔属性:对方当前是否正在输入
public var isTyping: Bool
/// 对方正在输入的设备平台列表(如 [.iOS])
public var activePlatforms: [IMPlatform]
}
3. 聊天页完整接入示例
import SwiftUI
import QXJIMSDK
@MainActor
@Observable
final class ChatTypingViewModel {
let conversationID: String
let peerUserID: String
var isPeerTyping: Bool = false
init(conversationID: String, peerUserID: String) {
self.conversationID = conversationID
self.peerUserID = peerUserID
}
/// 在输入框文本变化时调用
func onInputTextChanged(_ newText: String) {
let hasText = !newText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
Task {
try? await QXJIMClient.shared.changeInputStates(
conversationID: conversationID,
focus: hasText
)
}
}
/// 监听对方输入状态变化(绑定在聊天视图的 .task {} 中)
func observePeerTyping() async {
for await event in QXJIMClient.shared.inputStatusEvents.stream() {
guard event.conversationID == conversationID,
event.userID == peerUserID else {
continue
}
self.isPeerTyping = event.isTyping
}
}
}