SwiftUI中如何用系统原生UIBarButtonItem实现导航栏Cancel/Done按钮?
在SwiftUI中使用系统原生导航栏Cancel/Done按钮
没问题,我来帮你搞定这个事儿!你完全不用自己手动维护多语言翻译,SwiftUI里照样能复用系统原生的导航栏按钮,而且实现起来比你想的简单——根本不用绕UIViewRepresentable,直接用SwiftUI的Toolbar就能搞定。
最简洁的实现方案(推荐)
直接用Text搭配LocalizedStringKey,SwiftUI会自动匹配系统原生的本地化翻译,效果和UIKit里用UIBarButtonSystemItem完全一致:
import SwiftUI struct SettingsDialog: View { // 假设用这个绑定控制对话框的显示/隐藏 @Binding var isShowingDialog: Bool var body: some View { NavigationStack { // iOS 16及以上用NavigationStack,iOS 13-15换成NavigationView Form { // 这里放你的可编辑设置内容,比如文本输入、开关等 Section { TextField("昵称", text: .constant("")) Toggle("启用夜间模式", isOn: .constant(false)) } } .navigationTitle("设置") .toolbar { // 左侧Cancel按钮,调用系统原生翻译 ToolbarItem(placement: .navigationBarLeading) { Button(action: { isShowingDialog = false // 这里加Cancel按钮的逻辑,比如放弃修改 }) { Text(.init("Cancel")) } } // 右侧Done按钮,同样用系统原生翻译 ToolbarItem(placement: .navigationBarTrailing) { Button(action: { isShowingDialog = false // 这里加Done按钮的逻辑,比如保存设置 }) { Text(.init("Done")) } } } } } } // 预览用 struct SettingsDialog_Previews: PreviewProvider { static var previews: some View { SettingsDialog(isShowingDialog: .constant(true)) } }
为什么这个方法能拿到原生翻译?
当你给Text传入LocalizedStringKey(比如Text(.init("Cancel"))),SwiftUI会自动去查找系统级的本地化字符串,和UIKit里用UIBarButtonSystemItem.cancel得到的翻译完全一样,不用你手动维护多语言文件。
如果你偏好用UIKit的UIBarButtonItem(备选方案)
如果你就是想完全复用UIKit的UIBarButtonItem,也可以用UIViewControllerRepresentable做个小封装,不过这个方案不如上面的简洁,仅供参考:
struct SystemBarButton: UIViewControllerRepresentable { let systemItem: UIBarButtonItem.SystemItem let onTap: () -> Void func makeUIViewController(context: Context) -> UIViewController { let vc = UIViewController() let barButton = UIBarButtonItem(barButtonSystemItem: systemItem, target: context.coordinator, action: #selector(Coordinator.handleTap)) // 这里可以改leftBarButtonItem或rightBarButtonItem vc.navigationItem.leftBarButtonItem = barButton return vc } func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator(action: onTap) } class Coordinator: NSObject { private let action: () -> Void init(action: @escaping () -> Void) { self.action = action } @objc func handleTap() { action() } } } // 使用的时候这样写 ToolbarItem(placement: .navigationBarLeading) { SystemBarButton(systemItem: .cancel) { isShowingDialog = false } }
总的来说,第一种方案更符合SwiftUI的设计风格,代码更简洁,还能完美拿到系统原生的多语言支持,优先推荐用这个~
内容的提问来源于stack exchange,提问作者dankito
相关产品推荐
相关产品推荐

