@AppStorage var inside ScrollViewReader does not update view
Asked Answered
W

1

2

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)

Walrath answered 11/10, 2023 at 12:54 Comment(3)
Something happened to AppStorage recently and it isn’t working as it should, you should report a bug.Photomural
I'm on Xcode 14.2. Reported the bug.Walrath
this may be related, you can add that report number with your reportPhotomural
W
3

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.

Walrath answered 11/10, 2023 at 18:23 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.