@AppStorage在ScrollViewReader内无法更新视图的问题咨询
问题:@AppStorage在ScrollViewReader内无法触发视图更新
现象描述
使用@AppStorage定义的fontSize变量,修改时能正常更新外部文本的字体大小,但ScrollViewReader内部的文本完全没有响应。移除ScrollViewReader或将@AppStorage替换为@State后,视图更新恢复正常。
代码示例
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)
问题原因
这是Xcode 14.2对应SwiftUI版本的已知bug:ScrollViewReader的闭包内部无法正确追踪外部@AppStorage变量的变化。
@AppStorage本质是绑定到UserDefaults的持久化状态,其依赖更新依赖通知机制,但该版本的ScrollViewReader视图树遗漏了这一通知的监听;@State是本地视图状态,依赖追踪逻辑更直接,因此能正常触发视图更新。
修复方案
方案1:手动绑定ID触发更新
给ScrollViewReader内部的目标视图添加与fontSize绑定的id,强制SwiftUI识别依赖变化:
ScrollViewReader { proxy in ScrollView { Text("Hello, bigger world!") .font(.system(size: CGFloat(fontSize))) .id(fontSize) // 绑定fontSize作为ID,触发视图刷新 } }
方案2:抽分子视图传递参数
将ScrollView内部的内容抽成独立子视图,通过参数传递fontSize,利用SwiftUI的视图参数依赖追踪机制触发更新:
struct ContentView: View { @AppStorage("fontSize") var fontSize: Int = 12 var body: some View { VStack { // ... 其他代码不变 ScrollViewReader { proxy in ScrollView { ScrollContent(fontSize: fontSize) // 调用子视图 } } // ... 其他代码不变 } } } // 子视图 struct ScrollContent: View { let fontSize: Int var body: some View { Text("Hello, bigger world!") .font(.system(size: CGFloat(fontSize))) } }
方案3:升级Xcode版本
该bug在Xcode 15及以上版本的SwiftUI中已被修复,升级到最新Xcode可彻底解决问题。
内容的提问来源于stack exchange,提问作者soundflix
相关产品推荐
相关产品推荐

