I've tried several solutions that I've found but none work for me, mostly lengthy with compile errors that I didn't understand how to fix. I collaborated with an AI today and after the third iteration edited this compact solution that compiled - but the List still does not scroll automatically. I'm very, very new at Swift.
The backing Array of String is updated by a published and observableObject:
class Logger: ObservableObject {
@Published var messageArray = ["Start by selecting the project's data folder."]
func addMessage(_ msg: String) {
messageArray.append("\(timeNow()) * \(msg)")
}
I create an instance in my main (and only) ContentView
@ObservedObject var logger = Logger()
The code below is in a VStack and updates but does not scroll when the messageArray is changed by some other code. It is for macOS not IOS
List(logger.messageArray, id: \.self) {
message in
Text(message)
}
.padding()
.background(ScrollViewReader { proxy in
Color.clear.onAppear {
proxy.scrollTo(logger.messageArray.last)
}
.onReceive(logger.$messageArray) { _ in
withAnimation {
proxy.scrollTo(logger.messageArray.last)
}
}
})
I hope you can help me with this as I've spent way too much time on it.
You could try this approach, to scroll to the last line of the list.
It uses the important id
and .onChange()
and has the ScrollViewReader
wrapping the List
. Works for me.
class Logger: ObservableObject {
@Published var messageArray = ["message"]
func addMessage(_ msg: String) {
messageArray.append("\(UUID().uuidString.prefix(5)) * \(msg)") // <-- for testing
}
}
struct ContentView: View {
@StateObject var logger = Logger() // <-- here
var body: some View {
ScrollViewReader { proxy in
List (logger.messageArray, id: \.self) { message in
Text(message).id(message) // <-- here, need id
}
.onChange(of: logger.messageArray) { _ in // <-- here
withAnimation {
proxy.scrollTo(logger.messageArray.last)
}
}
.padding()
}
Button("Add message") {
logger.addMessage("test message") // <-- for testing
}
}
}