聊天 | 媒体 | 语音消息 | 附加功能 |
---|---|---|---|
![]() |
![]() |
![]() |
![]() |
像这样创建一个聊天视图
@State var messages: [Message] = []
var body: some View {
ChatView(messages: messages) { draft in
yourViewModel.send(draft: draft)
}
}
其中
messages
- 要显示的消息列表
didSendMessage
- 当用户按下发送按钮时调用的闭包
Message
是 Chat
用于内部实现的类型。在上面的代码中,它期望用户提供一个 Message
结构体列表,并在 didSendMessage
闭包中返回一个 DraftMessage
。您可以将它双向映射到您的 API 期望的自己的 Message
模型,或者按原样使用。
聊天类型 - 决定消息的顺序和新消息动画的方向。 可用选项
conversation
- 最新消息在底部,新消息从底部出现comments
- 最新消息在顶部,新消息从顶部出现回复模式 - 决定回复消息的外观。 可用选项
quote
- 当回复消息 A 时,新消息将显示为最新消息,并在其正文中引用消息 Aanswer
- 当回复消息 A 时,新消息将直接显示在消息 A 下方,作为一个单独的单元格,而不在其正文中复制消息 A要指定任何这些,请通过 init
传递它们
ChatView(messages: viewModel.messages, chatType: .comments, replyMode: .answer) { draft in
yourViewModel.send(draft: draft)
}
您可以像这样自定义消息单元格
ChatView(messages: viewModel.messages) { draft in
viewModel.send(draft: draft)
} messageBuilder: { message, positionInUserGroup, positionInCommentsGroup, showContextMenuClosure, messageActionClosure, showAttachmentClosure in
VStack {
Text(message.text)
if !message.attachments.isEmpty {
ForEach(message.attachments, id: \.id) { at in
AsyncImage(url: at.thumbnail)
}
}
}
}
messageBuilder
的参数
message
- 包含用户信息、附件等的消息positionInUserGroup
- 消息在其来自同一用户的连续消息集合中的位置positionInCommentsGroup
- 消息在其连续评论组中的位置(仅适用于 .answer ReplyMode,.quote 模式为 nil)showContextMenuClosure
- 用于显示消息上下文菜单的闭包messageActionClosure
- 传递用户交互的闭包,例如 .replyshowAttachmentClosure
- 您可以将附件传递给此闭包,以使用 ChatView 的全屏媒体查看器您可以像这样自定义输入视图(底部带有按钮的文本字段)
ChatView(messages: viewModel.messages) { draft in
viewModel.send(draft: draft)
} inputViewBuilder: { textBinding, attachments, inputViewState, inputViewStyle, inputViewActionClosure, dismissKeyboardClosure in
Group {
switch inputViewStyle {
case .message: // input view on chat screen
VStack {
HStack {
Button("Send") { inputViewActionClosure(.send) }
Button("Attach") { inputViewActionClosure(.photo) }
}
TextField("Write your message", text: textBinding)
}
case .signature: // input view on photo selection screen
VStack {
HStack {
Button("Send") { inputViewActionClosure(.send) }
}
TextField("Compose a signature for photo", text: textBinding)
.background(Color.green)
}
}
}
}
inputViewBuilder
的参数
textBinding
用于绑定您自己的 TextFieldattachments
是一个结构,包含照片、视频、录音和您正在回复的消息inputViewState
- 输入视图的状态,如果可能,由库自动控制,或者通过您对 inputViewActionClosure
的调用控制inputViewStyle
- .message
或 .signature
(聊天屏幕或照片选择屏幕)inputViewActionClosure
用于调用您自定义按钮上的点击。例如,如果您想使用自己的按钮发送消息,请调用 inputViewActionClosure(.send)
,然后库将重置文本和附件并调用 didSendMessage
发送闭包dismissKeyboardClosure
- 调用此方法以关闭键盘长按消息将显示此消息的菜单(可以关闭,请参阅修饰符)。 要定义自定义消息菜单操作,请声明一个符合 MessageMenuAction
的枚举。 然后,如果您将枚举的名称传递给它(请参阅代码示例),则库将在长按消息时显示您的自定义菜单选项,而不是默认选项。 选择操作后,将调用特殊的 callbcak。 这是一个简单的例子
enum Action: MessageMenuAction {
case reply, edit
func title() -> String {
switch self {
case .reply:
"Reply"
case .edit:
"Edit"
}
}
func icon() -> Image {
switch self {
case .reply:
Image(systemName: "arrowshape.turn.up.left")
case .edit:
Image(systemName: "square.and.pencil")
}
}
// Optional
// Implement this method to conditionally include menu actions on a per message basis
// The default behavior is to include all menu action items
static func menuItems(for message: ExyteChat.Message) -> [Action] {
if message.user.isCurrentUser {
return [.edit]
} else {
return [.reply]
}
}
}
ChatView(messages: viewModel.messages) { draft in
viewModel.send(draft: draft)
} messageMenuAction: { (action: Action, defaultActionClosure, message) in // <-- here: specify the name of your `MessageMenuAction` enum
switch action {
case .reply:
defaultActionClosure(message, .reply)
case .edit:
defaultActionClosure(message, .edit { editedText in
// update this message's text on your BE
print(editedText)
})
}
}
messageMenuAction
的参数
selectedMenuAction
- 用户从菜单中选择的操作。 注意:在声明此变量时,请显式指定其类型(您的 MessageMenuAction 的自定义后代)defaultActionClosure
- 采用 MessageMenuAction 的默认实现案例的闭包,该闭包提供简单的操作处理程序; 如果您需要它们,您可以调用此闭包,传递所选消息并选择默认操作之一(.reply,.edit); 或者您可以为您所有的操作编写自定义实现,在这种情况下,只需忽略此闭包即可message
- 显示菜单的消息在实现您自己的 MessageMenuActionClosure
时,编写一个 switch 语句,遍历您的 MessageMenuAction
的所有情况,在每种情况下编写您自己的操作处理程序,或调用默认的处理程序。 注意:并非所有的默认操作都能开箱即用 - 例如,对于 .edit
,您仍然需要提供一个闭包来将编辑后的文本保存在您的 BE 上。 请参阅 ChatExample 项目中的 CommentsExampleView,以获取 MessageMenuActionClosure 用法示例。
// Example: Adding Swipe Actions to your ChatView
ChatView(messages: viewModel.messages) { draft in
viewModel.send(draft: draft)
}
.swipeActions(edge: .leading, performsFirstActionWithFullSwipe: false, items: [
// SwipeActions are similar to Buttons, they accept an Action and a ViewBuilder
SwipeAction(action: onDelete, activeFor: { $0.user.isCurrentUser }, background: .red) {
swipeActionButtonStandard(title: "Delete", image: "xmark.bin")
},
// Set the background color of a SwipeAction in the initializer,
// instead of trying to apply a background color in your ViewBuilder
SwipeAction(action: onReply, background: .blue) {
swipeActionButtonStandard(title: "Reply", image: "arrowshape.turn.up.left")
},
// SwipeActions can also be selectively shown based on the message,
// here we only show the Edit action when the message is from the current sender
SwipeAction(action: onEdit, activeFor: { $0.user.isCurrentUser }, background: .gray) {
swipeActionButtonStandard(title: "Edit", image: "bubble.and.pencil")
}
])
swipeActions
的参数
edge
- 消息的前导或尾随边缘performsFirstActionWithFullSwipe
- 如果为 true,则完全滑动将触发 items
列表中提供的第一个 SwipeAction
items
- 要包含的 SwipeAction
列表这些使用 AnyView
,所以请尽量保持它们足够简单
betweenListAndInputViewBuilder
- 在聊天列表视图和输入视图之间显示的内容mainHeaderBuilder
- 整个聊天的标题,它将与所有消息和标题一起滚动headerBuilder
- 日期部分标题构建器isListAboveInputView
- 消息表格是否在输入字段视图上方
showDateHeaders
- 显示带有日期的部分标题,默认为 true
isScrollEnabled
- 禁止消息的 UITabelView
滚动
showMessageMenuOnLongPress
- 打开/关闭长按时显示菜单
showNetworkConnectionProblem
- 打开/关闭显示网络错误
assetsPickerLimit
- 设置库中内置的 MediaPicker 的限制
setMediaPickerSelectionParameters
- 包含 MediaPicker 选择参数的结构(assetsPickerLimit 和其他参数,如 mediaType,selectionStyle 等)。
orientationHandler
- 处理屏幕旋转
enableLoadMore(offset: Int, handler: @escaping ChatPaginationClosure)
- 当用户从末尾滚动到第 offset
条消息时,调用处理函数,以便用户可以加载更多消息。 注意:除非向上滚动到最顶部,否则新消息不会出现在聊天中 - 这是一种优化。
您可以使用 chatTheme
自定义默认 UI 的颜色和图像。 您可以传递所有/一些颜色和图像
.chatTheme(
ChatTheme(
colors: .init(
mainBackground: .red,
buttonBackground: .yellow,
addButtonBackground: .purple
),
images: .init(
camera: Image(systemName: "camera")
)
)
)
请以类似的方式使用 mediaPickerTheme
来自定义内置的照片选择器。
avatarSize
- 默认的头像是一个圆形,您可以在此处指定其直径 tapAvatarClosure
- 点击头像时调用的闭包
messageUseMarkdown
- 使用 markdown(例如 ** 使某些内容加粗)或不使用 showMessageTimeView
- 在消息的角落显示时间戳
setMessageFont
- 传递自定义字体以用于消息
setAvailableInput
- 隐藏默认 InputView 中的某些按钮。 可用选项为: - .full
- 媒体 + 文本 + 音频
- .textAndMedia
- .textAndAudio
- .textOnly
您可以使用标准的 SwiftUI 本地化过程来本地化输入,并将输入字符串添加到每种语言的 Localizable.strings 文件中。
该库使用以下可以本地化的文本
有 2 个示例项目
GoogleService-Info
替换为您自己的。 之后,您可以在多个模拟器/设备上进行测试。创建您的 Firestore 应用 https://console.firebase.google.com/ 创建 Firestore 数据库(用于轻量级文本数据)https://firebase.google.com/docs/firestore/manage-data/add-data 创建 Cloud Firestore 数据库(用于图像和录音) https://firebase.google.com/docs/storage/web/start
尝试 Chat 示例
git clone git@github.com:exyte/Chat.git
cd <ChatRepo>/Example
dependencies: [
.package(url: "https://github.com/exyte/Chat.git")
]
pod 'ExyteChat'
github "Exyte/Chat"
PopupView - Toast 和弹窗库
Grid - 最强大的 Grid 容器
ScalingHeaderScrollView - 带有粘性标题的滚动视图,滚动时标题会缩小
AnimatedTabBar - 带有多个预设动画的选项卡栏
MediaPicker - 可定制的媒体选择器
OpenAI 用于 OpenAI REST API 的 Wrapper 库
AnimatedGradient - 动画线性渐变
ConcentricOnboarding - 动画引导流程
FloatingButton - 悬浮按钮菜单
ActivityIndicatorView - 多个动画加载指示器
ProgressIndicatorView - 多个动画进度指示器
FlagAndCountryCode - 每个国家/地区的电话代码和标志
SVGView - SVG 解析器
LiquidSwipe - 流体导航动画