- ChatViewModel needs to be @EnvironmentObject so that the combine effect can be reflected in multiple views. If set to @ObservedObject, then SwiftUI cannot capture the change.
Example
struct ChatModel: Hashable {
var message: String
var avator: String
var sendByMe: Bool
}
import SwiftUI
struct ChatView: View {
@EnvironmentObject var model: ChatViewModel
var body: some View {
VStack {
List {
ForEach(model.messages, id: \.self) { msg in
ChatRowView(msgModel: msg)
}
}
.listStyle(SidebarListStyle())
.frame(minHeight: 0, maxHeight: .infinity)
ChatButtomView()
}
}
}
struct ChatRowView: View {
@EnvironmentObject var home: HomeGlobal
var msgModel: ChatModel
@ViewBuilder
var body: some View {
if msgModel.sendByMe {
HStack {
Spacer()
Text(msgModel.message)
.padding(home.defaultPadding/3)
.font(home.fontBody)
.background(Color.green)
.cornerRadius(6)
Image(msgModel.avator)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: home.defaultPadding*2, height: home.defaultPadding*2)
}
} else {
HStack {
Image(msgModel.avator)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: home.defaultPadding*2, height: home.defaultPadding*2)
Text(msgModel.message)
.padding(home.defaultPadding/3)
.font(home.fontBody)
.background(Color.white)
.cornerRadius(6)
Spacer()
}
}
}
}
struct ChatButtomView: View {
@EnvironmentObject var home: HomeGlobal
@EnvironmentObject var model: ChatViewModel
@State var msgText: String = ""
var body: some View {
HStack {
Image(systemName: "speaker.3")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: home.defaultPadding*1.5)
TextField("Input message", text: $msgText)
.frame(height: home.defaultPadding*2)
.background(Color.white)
.cornerRadius(home.cornerRadius)
Image(systemName: "smiley")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: home.defaultPadding*1.5)
.padding(.trailing, home.defaultPadding)
Button(action: {
if msgText != "" {
sendMsg(msg: msgText)
}
}, label: {
Image(systemName: "plus.circle")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: home.defaultPadding*1.5)
})
}
.padding(.top, home.defaultPadding/2)
.padding(.horizontal)
.padding(.bottom, home.defaultPadding*2)
.background(Color.gray.opacity(0.2))
// .offset(y: -home.defaultPadding/2)
}
func sendMsg(msg: String) {
let newMsg = ChatModel(message: msg, avator: "avator6", sendByMe: true)
model.sendMessage(msg: newMsg)
msgText = ""
}
}
import Foundation
import SwiftUI
import Combine
class ChatViewModel: ObservableObject {
@Published var messages = [
ChatModel(message: "Hello.", avator: "avator1", sendByMe: false),
ChatModel(message: "I had breakfast.", avator: "avator2", sendByMe: false),
ChatModel(message: "I slept very well.", avator: "avator3", sendByMe: false)
]
var didChange = PassthroughSubject<Void, Never>()
func sendMessage(msg: ChatModel) {
messages.append(msg)
didChange.send()
}
}