I have an issue with @AppStorage and ScrollViewReader
that seems like a bug.
My @AppStorage variable fontSize
is supposed to adjust the text size inside a ScrollViewReader
. However, when its value changes, it does not update the view.
When I remove ScrollViewReader
or change @AppStorage to @State, it will update.
What's wrong and how can I fix it?
import SwiftUI
struct ContentView: View {
@AppStorage("fontSize") var fontSize: Int = 12
// @State var fontSize: Int = 12
var body: some View {
VStack {
Text("Hello, bigger world!")
.font(.system(size: CGFloat(fontSize)))
ScrollViewReader { proxy in
ScrollView {
Text("Hello, bigger world!")
// @AppStorage var inside ScrollViewReader does not update?
.font(.system(size: CGFloat(fontSize)))
}
}
Button("toggle font size") {
fontSize += 2
}
.keyboardShortcut("+")
Text("\(fontSize)")
}
.padding()
.fixedSize()
.onAppear {
DispatchQueue.main.async {
fontSize = 12
}
}
}
}
macOS 12.6.9, Xcode 14.2 (SDK macOS 13.1)
I found my own solution, analogous to this solution for GeometryReader
.
I split the ScrollView
to a separate view:
import SwiftUI
struct ContentView: View {
@AppStorage("fontSize") var fontSize: Int = 12
var body: some View {
VStack {
Text("Hello, bigger world!")
.font(.system(size: CGFloat(fontSize)))
ScrollViewReader { proxy in
ScrollViewContainer(fontSize: $fontSize, proxy: proxy)
}
Button("toggle font size") {
fontSize += 2
}
.keyboardShortcut("+")
Text("\(fontSize)")
}
.padding()
.fixedSize()
.onAppear {
DispatchQueue.main.async {
fontSize = 12
}
}
}
}
/// A Container view to make @AppStorage value binding work (SwiftUI bug)
struct ScrollViewContainer: View {
@Binding var fontSize: Int
var proxy: ScrollViewProxy
var body: some View {
ScrollView {
Text("Hello, bigger world!")
.font(.system(size: CGFloat(fontSize)))
}
}
}
Using proxy
with .scrollTo(ID)
in this new view also works, which is the whole point of having ScrollViewReader
.