跳到主要内容

“对方正在输入”状态 (Typing)

QXJIMSDK 基于 Go 核心层 internal/conversation_msg/entering.go 状态机,提供多端感知、自带节流与超时自动清理的“正在输入”状态能力。


1. 核心机制说明​

  1. 发送端自动 10 秒节流 (inputStatesSendTime = 10s):
    • 当用户在输入框连续打字、每敲击一个字符都调用 changeInputStates(conversationID: ..., focus: true) 时,Go 核心层会通过内存缓存拦截 10 秒内的重复 focus: true 调用,每 10 秒最多发送一次信令包,业务层无需自己写防抖/节流定时器。
    • 当用户清空输入框、点击发送按钮或退出聊天页时,调用 changeInputStates(conversationID: ..., focus: false),会立即通知对方停止展示“正在输入...”。
  2. 接收端 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
}
}
}