Reputation: 47
I am working on a SwiftUI chat application where I want the chat view to automatically scroll to the last message when the view appears and when new messages are added. The scrolling works fine for text messages, but when I include images in the chat messages, it stops scrolling to the last message.
My code in FirebaseManager:
struct UserData: Identifiable {
var id = UUID()
var username: String
var profileImageURL: URL?
var firstName: String
}
struct Message: Identifiable, Equatable, Hashable {
var id = UUID()
var text: String
var senderID: String
var recipientUsername: String
var timestamp: Date // Används för att ordna meddelandena efter tidpunkt
var imageURL: URL?
var timeAgo: String {
let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .abbreviated
return formatter.localizedString(for: timestamp, relativeTo: Date())
}
}
My code in ChatLogViewModel:
class ChatLogViewModel: ObservableObject {
@Published var messages: [Message] = []
func fetchMessages() {
firebaseManager.fetchMessages { messages in
DispatchQueue.main.async {
self.messages = messages
}
}
}
}
My code in MessageView:
import SwiftUI
struct MessageView: View {
let message: Message
let isCurrentUser: Bool
var body: some View {
VStack(alignment: isCurrentUser ? .trailing : .leading) {
if let imageURL = message.imageURL {
AsyncImage(url: imageURL) { phase in
switch phase {
case .empty:
ProgressView()
case .success(let image):
image
.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: 200, maxHeight: 200)
.cornerRadius(10)
case .failure:
Text("Failed to load image")
@unknown default:
EmptyView()
}
}
}
if !message.text.isEmpty {
Text(message.text)
.foregroundColor(isCurrentUser ? .white : .black)
.padding()
.background(isCurrentUser ? Color.blue : Color.white)
.cornerRadius(10)
.overlay(
MessageOverlay(isCurrentUser: isCurrentUser)
)
}
}
}
}
struct MessageOverlay: View {
let isCurrentUser: Bool
var body: some View {
Image(systemName: "arrowtriangle.down.fill")
.font(.title)
.rotationEffect(.degrees(isCurrentUser ? -45 : 45))
.offset(x: isCurrentUser ? 10 : -10, y: 10)
.foregroundColor(isCurrentUser ? Color.blue : Color.white)
}
}
My code in MessageRow:
import SwiftUI
struct MessageRow: View {
let message: Message
let isCurrentUser: Bool
var body: some View {
HStack {
if isCurrentUser {
Spacer()
MessageView(message: message, isCurrentUser: isCurrentUser)
} else {
MessageView(message: message, isCurrentUser: isCurrentUser)
Spacer()
}
}
}
}
My code in ChatLogView:
import SwiftUI
struct ChatLogView: View {
let user: UserData
@StateObject var chatLogViewModel = ChatLogViewModel()
var firebaseManager: FirebaseManager
var body: some View {
VStack {
ScrollView {
ScrollViewReader { scrollViewProxy in
VStack {
ForEach(chatLogViewModel.messages) { message in
MessageRow(message: message, isCurrentUser: message.senderID == firebaseManager.currentUserUID)
.padding(.horizontal)
.padding(.top, 8)
}
HStack { Spacer() }
.id("lastMessage")
}
.onAppear {
print("Chat view appeared, scrolling to last message")
scrollViewProxy.scrollTo("lastMessage", anchor: .bottom)
}
.onChange(of: chatLogViewModel.messages) { _ in
print("Messages changed, scrolling to last message")
withAnimation(.easeOut(duration: 0.5)) {
scrollViewProxy.scrollTo("lastMessage", anchor: .bottom)
}
}
}
}
}
.background(Color.gray.opacity(0.2))
.navigationTitle(user.username)
.navigationBarTitleDisplayMode(.inline)
.toolbar(.hidden, for: .tabBar)
ChatBarComponent(chatLogViewModel: chatLogViewModel, user: user)
}
}
Chat view appeared, scrolling to last message
Messages changed, scrolling to last message
Any help or suggestions would be greatly appreciated!
Upvotes: 0
Views: 72