SwiftUI中如何将导航栏按钮动作绑定至ViewControllerWrapper
解决SwiftUI导航按钮调用UIKit ViewController方法的问题
针对混合UIKit与SwiftUI技术栈的场景,要让SwiftUI导航栏按钮触发UIKit侧ClockMainViewController的指定方法,这里提供两种实用方案,同时替换掉废弃的navigationBarItemsAPI:
方案1:基于SwiftUI单向数据流的Binding触发法
这种方法符合SwiftUI的设计理念,通过@Binding传递触发信号,在UIKit封装器中响应并调用目标方法。
步骤1:修改ClockMainViewControllerWrapper
import SwiftUI struct ClockMainViewControllerWrapper: UIViewControllerRepresentable { // 绑定触发信号,用于通知UIKit侧执行方法 @Binding var shouldTriggerEdit: Bool func makeUIViewController(context: Context) -> ClockMainViewController { ClockMainViewController() } func updateUIViewController(_ uiViewController: ClockMainViewController, context: Context) { // 当触发信号变为true时,调用目标方法并重置信号 guard shouldTriggerEdit else { return } uiViewController.startEditTransition() // 替换为你实际要调用的方法名 shouldTriggerEdit = false } }
步骤2:在SwiftUI主视图中使用
struct MainMenuView: View { // 定义触发状态变量 @State private var triggerClockEdit = false var body: some View { NavigationStack { // iOS 16+用NavigationStack,iOS 15及以下用NavigationView ClockMainViewControllerWrapper(shouldTriggerEdit: $triggerClockEdit) .navigationTitle("title") .navigationBarTitleDisplayMode(.inline) .toolbar { // 用ToolbarItem替代废弃的navigationBarItems ToolbarItem(placement: .navigationBarTrailing) { Button(action: { // 切换触发状态 triggerClockEdit = true }) { Image(systemName: "pencil") } } } } } }
方案2:直接持有ViewController引用(更直接)
如果不需要严格遵循SwiftUI数据流,可通过ObservableObject持有ViewController的弱引用,直接调用方法。
步骤1:定义引用管理类
import SwiftUI class ClockVCReference: ObservableObject { // 弱引用避免内存泄漏 weak var viewController: ClockMainViewController? }
步骤2:修改ClockMainViewControllerWrapper
struct ClockMainViewControllerWrapper: UIViewControllerRepresentable { @ObservedObject var vcReference: ClockVCReference func makeUIViewController(context: Context) -> ClockMainViewController { let vc = ClockMainViewController() vcReference.viewController = vc return vc } func updateUIViewController(_ uiViewController: ClockMainViewController, context: Context) {} }
步骤3:在SwiftUI主视图中使用
struct MainMenuView: View { @StateObject private var clockVCRef = ClockVCReference() var body: some View { NavigationStack { ClockMainViewControllerWrapper(vcReference: clockVCRef) .navigationTitle("title") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button(action: { // 直接调用ViewController的方法,注意判空 clockVCRef.viewController?.startEditTransition() }) { Image(systemName: "pencil") } } } } } }
关键注意点
- 废弃API替换:务必用
toolbar+ToolbarItem替代navigationBarItems,这是SwiftUI当前的标准实现。 - 内存安全:所有对UIKit ViewController的引用必须用
weak,防止循环引用导致内存泄漏。 - 方法调用时机:方案1通过
updateUIViewController确保ViewController已完成初始化;方案2需注意判空,避免ViewController未加载时调用方法。
内容的提问来源于stack exchange,提问作者Dru Freeman
相关产品推荐
相关产品推荐

