You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

@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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 16:13:36