You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

SwiftUI双语App切换语言后导航栏标题不更新的问题求助

SwiftUI双语App切换语言后导航栏标题不更新的问题求助

嘿,我碰到个SwiftUI双语开发的小难题,来求助各位大佬!

我做了一个双语App,已经配置好Localizable.strings文件了,大部分界面切换语言都能正常更新,但导航栏标题总是掉链子:

  • 第一次切换语言时,导航栏标题完全没反应;
  • 要是跳转到另一个带导航栏标题的页面,新页面的标题会变成切换后的语言,但返回原页面再切语言,原页面的导航栏标题还是纹丝不动;
  • 像TabView这些其他组件的语言切换都完全正常,就导航栏这部分搞不定。

附上我的代码片段:

struct CategoryView: View {
    @AppStorage("selectedLanguage") private var selectedLanguage: String = "pl"
    
    var body: some View {
        NavigationStack {
            Text("Category")
            
            Button("ChnageLanguageEn") {
                selectedLanguage = "en"
            }

            Button("ChnageLanguagePl") {
                selectedLanguage = "pl"
            }
            .navigationBarTitleDisplayMode(.inline)
            // 省略其他代码
        }
    }
}

有没有大佬知道怎么解决这个导航栏标题不更新的问题呀?下面我也整理了几个试过的可行方案,供大家参考:

方案1:用ObservableObject管理语言状态,触发全局刷新

@AppStorage虽然能持久化数据,但对导航栏这种嵌套视图的更新触发不够及时。可以搞个专门的语言管理类,用@Published属性触发视图刷新:

class LanguageManager: ObservableObject {
    @Published var selectedLanguage: String = UserDefaults.standard.string(forKey: "selectedLanguage") ?? "pl" {
        didSet {
            UserDefaults.standard.set(selectedLanguage, forKey: "selectedLanguage")
            // 主动发送更新通知
            objectWillChange.send()
        }
    }
}

然后在App入口把这个管理类注入环境:

@main
struct YourApp: App {
    @StateObject private var languageManager = LanguageManager()
    
    var body: some Scene {
        WindowGroup {
            CategoryView()
                .environmentObject(languageManager)
                .environment(\.locale, Locale(identifier: languageManager.selectedLanguage))
        }
    }
}

最后在页面里使用环境对象,并且导航栏标题用本地化字符串:

struct CategoryView: View {
    @EnvironmentObject private var languageManager: LanguageManager
    
    var body: some View {
        NavigationStack {
            Text(NSLocalizedString("Category", comment: "分类页面标题"))
            
            Button(NSLocalizedString("ChangeLanguageEn", comment: "切换英文按钮")) {
                languageManager.selectedLanguage = "en"
            }

            Button(NSLocalizedString("ChangeLanguagePl", comment: "切换波兰语按钮")) {
                languageManager.selectedLanguage = "pl"
            }
            .navigationTitle(NSLocalizedString("CategoryTitle", comment: "分类页面导航栏标题"))
            .navigationBarTitleDisplayMode(.inline)
        }
        .environment(\.locale, Locale(identifier: languageManager.selectedLanguage))
    }
}

方案2:给NavigationStack加动态ID,强制重建视图

这个方法简单粗暴,给NavigationStack设置一个和语言绑定的ID,当语言变化时,SwiftUI会直接重建整个导航栈,自然就更新标题了:

struct CategoryView: View {
    @AppStorage("selectedLanguage") private var selectedLanguage: String = "pl"
    
    var body: some View {
        NavigationStack {
            Text(NSLocalizedString("Category", comment: "分类页面标题"))
            
            Button(NSLocalizedString("ChangeLanguageEn", comment: "切换英文按钮")) {
                selectedLanguage = "en"
            }

            Button(NSLocalizedString("ChangeLanguagePl", comment: "切换波兰语按钮")) {
                selectedLanguage = "pl"
            }
            .navigationTitle(NSLocalizedString("CategoryTitle", comment: "分类页面导航栏标题"))
            .navigationBarTitleDisplayMode(.inline)
        }
        .id(selectedLanguage) // 语言变化时重建导航栈
        .environment(\.locale, Locale(identifier: selectedLanguage))
    }
}

小提醒

记得所有需要本地化的文本都要用NSLocalizedString,别直接写死字符串,不然切换语言也不会生效哦!

备注:内容来源于stack exchange,提问作者Filip Kaźmierczak

火山引擎 最新活动