SwiftUI如何通过Picker调整字体大小并持久化用户选择
解决方案
问题1:Picker选中值同步更新全局字体
你之前尝试的EnvironmentObject方案是正确的,只需要把状态托管到全局可观测对象里,不需要额外加onChange修饰符,数据变更后会自动刷新所有引用的页面:
- 首先新建全局字体配置类,用来统一管理字体相关状态:
import SwiftUI class FontSettings: ObservableObject { // 字号对应关系,可根据需求调整实际数值 private let fontSizeMap: [Int: CGFloat] = [ 1: 12, // 极小 2: 14, // 小 3: 16, // 中(默认) 4: 18, // 大 5: 20 // 极大 ] // 字体名对应关系,后续加自定义字体时直接修改即可 private let fontNameMap: [Int: String] = [ 1: "System", 2: "Font2", 3: "Font3", // 其余字体对应关系自行补充 ] // 对外暴露的计算属性,直接返回可用的Font实例 var selectedFont: Font { let size = fontSizeMap[fontSizeIndex] ?? 16 let fontName = fontNameMap[fontIndex] ?? "System" if fontName == "System" { return .system(size: size) } else { return .custom(fontName, size: size) } } // 字体大小和字体选择的存储属性 @Published var fontSizeIndex = 3 @Published var fontIndex = 1 }
- 在你的App根入口注入全局实例,找到项目中带
@main标记的入口文件,修改为如下结构:
@main struct BibleApp: App { // 初始化全局字体配置,整个App生命周期内只会创建一次 @StateObject private var fontSettings = FontSettings() var body: some Scene { WindowGroup { // 这里替换成你自己的根视图,比如TabView或者NavigationStack的根 ContentView() // 注入全局字体配置,所有子视图都可以读取 .environmentObject(fontSettings) } } }
- 修改设置页代码,把局部@State替换成全局的环境对象:
import SwiftUI struct Setting: View { // 读取全局字体配置 @EnvironmentObject var fontSettings: FontSettings var body: some View { NavigationView { ScrollView { Form { Section(header: Text("文本设置")) { Picker(selection: $fontSettings.fontSizeIndex, label: Text("字体大小"), content: { Text("极小").tag(1) Text("小").tag(2) Text("中").tag(3) Text("大").tag(4) Text("极大").tag(5) }) Picker(selection: $fontSettings.fontIndex, label: Text("字体"), content: { Text("默认字体").tag(1) Text("字体2").tag(2) Text("字体3").tag(3) Text("字体4").tag(4) Text("字体5").tag(5) Text("字体6").tag(6) Text("字体7").tag(7) }) } } .frame(height:280) } } }
- 修改经文展示页代码,直接使用全局配置的字体:
import SwiftUI struct Scripture: View { // 读取全局字体配置 @EnvironmentObject var fontSettings: FontSettings var body: some View { ScrollView { Text("Hih in Zeisu Khazih khang ciamtehna ahi hi...") // 保留你原有的经文内容 // 直接用全局配置的字体即可,切换Picker会自动更新 .font(fontSettings.selectedFont) .foregroundColor(.primary) .multilineTextAlignment(.leading) .lineSpacing(5) .padding() } } } // 预览的时候记得注入实例,不然预览会报错 struct Scripture_Previews: PreviewProvider { static var previews: some View { Scripture() .environmentObject(FontSettings()) } }
问题2:选中值持久化保存
Canvas预览每次重启都会重置是正常现象,因为预览环境每次都会重新初始化所有实例。如果不做持久化处理,正式打包运行后App重启也会重置为默认值,只需要把FontSettings类里的@Published属性替换为@AppStorage即可自动实现持久化,修改后的FontSettings类存储部分代码如下:
class FontSettings: ObservableObject { // 前面的字号、字体映射和selectedFont计算属性保持不变 // ... // 用@AppStorage替换@Published,自动存到UserDefaults,重启App自动读取 @AppStorage("fontSizeIndex") var fontSizeIndex = 3 @AppStorage("fontIndex") var fontIndex = 1 }
@AppStorage是SwiftUI对UserDefaults的封装,数据会存在系统的UserDefaults里,卸载App才会清空,完全满足普通配置项的持久化需求。
内容的提问来源于stack exchange,提问作者Lian
相关产品推荐
相关产品推荐

