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

SwiftUI如何通过Picker调整字体大小并持久化用户选择

解决方案

问题1:Picker选中值同步更新全局字体

你之前尝试的EnvironmentObject方案是正确的,只需要把状态托管到全局可观测对象里,不需要额外加onChange修饰符,数据变更后会自动刷新所有引用的页面:

  1. 首先新建全局字体配置类,用来统一管理字体相关状态:
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
}
  1. 在你的App根入口注入全局实例,找到项目中带@main标记的入口文件,修改为如下结构:
@main
struct BibleApp: App {
    // 初始化全局字体配置,整个App生命周期内只会创建一次
    @StateObject private var fontSettings = FontSettings()
    
    var body: some Scene {
        WindowGroup {
            // 这里替换成你自己的根视图,比如TabView或者NavigationStack的根
            ContentView()
                // 注入全局字体配置,所有子视图都可以读取
                .environmentObject(fontSettings)
        }
    }
}
  1. 修改设置页代码,把局部@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)
            }
      }
}
  1. 修改经文展示页代码,直接使用全局配置的字体:
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 21:57:04