Hello !
This will be my first blog post. I hope I will find the solution.
So, I try to use the new iOS 17+ API for ScrollView. I have an array of messages that I want to show in scroll view.
And I need to scroll to bottom when I tap to Send button. When I use scrollPosition(id:anchor:), it freeze the UI. The link to the screencast to demonstrate. I think the problem might be the keyboard when it shows and hides. But I can't understand what can I do.
struct ChatView: View {
@ObservedObject var viewModel: CoachViewModel
@State private var scrollTo: Message.ID?
var body: some View {
ScrollView {
LazyVStack {
ForEach(viewModel.messages) { message in
MessageView(viewModel: viewModel, message: message)
}
}
.scrollTargetLayout()
}
.scrollPosition(id: $scrollTo)
.background(.primaryBackground)
.onChange(of: viewModel.scrollToBottom) {
if $1, let lastMessage = viewModel.messages.last {
withAnimation {
scrollTo = lastMessage.id
}
viewModel.scrollToBottom = false
}
}
}
}
struct Message: Identifiable, Hashable {
let id: UUID
let author: MessageAuthor
let text: String
}
final class CoachViewModel: ObservableObject {
@Published var messageTextInput = ""
@Published var scrollToBottom = false
@Published var messages: [Message] = [...]
// ... more code ...
func sendMessage() {
messages.append(
.init(
id: .init(),
author: .user,
text: messageTextInput
)
)
messageTextInput.removeAll()
scrollToBottom = true
}
}
struct CoachView: View {
@StateObject private var viewModel = CoachViewModel()
@State private var isSearching = false
var body: some View {
VStack(spacing: 0) {
Group {
CoachTitleView(viewModel: viewModel, isSearching: $isSearching)
ChatView(viewModel: viewModel)
}
.onTapGesture {
UIApplication.shared.endEditing()
}
if isSearching {
MatchboxView(viewModel: viewModel)
} else {
InputTextFieldView(viewModel: viewModel)
}
}
}
}