Here is my example/solution.
var scrollView : some View {
ScrollView(.vertical) {
ScrollViewReader { scrollView in
ForEach(self.messagesStore.messages) { msg in
VStack {
OutgoingPlainMessageView() {
Text(msg.message).padding(.all, 20)
.foregroundColor(Color.textColorPrimary)
.background(Color.colorPrimary)
}.listRowBackground(Color.backgroundColorList)
Spacer()
}
// 1. First important thing is to use .id
//as identity of the view
.id(msg.id)
.padding(.leading, 10).padding(.trailing, 10)
}
// 2. Second important thing is that we are going to implement //onChange closure for scrollTarget change,
//and scroll to last message id
.onChange(of: scrollTarget) { target in
withAnimation {
scrollView.scrollTo(target, anchor: .bottom)
}
}
// 3. Third important thing is that we are going to implement //onChange closure for keyboardHeight change, and scroll to same //scrollTarget to bottom.
.onChange(of: keyboardHeight){ target in
if(nil != scrollTarget){
withAnimation {
scrollView.scrollTo(scrollTarget, anchor: .bottom)
}
}
}
//4. Last thing is to add onReceive clojure, that will add an action to perform when this ScrollView detects data emitted by the given publisher, in our case messages array.
// This is the place where our scrollTarget is updating.
.onReceive(self.messagesStore.$messages) { messages in
scrollView.scrollTo(messages.last!.id, anchor: .bottom)
self.scrollTarget = messages.last!.id
}
}
}
}
Also take a look at my article on medium.
https://mehobega.medium.com/auto-scrollview-using-swiftui-and-combine-framework-b3e40bb1a99f