如何在SwiftUI中处理UIViewControllerRepresentable封装的TableViewController导航?
在SwiftUI中复用UIKit联系人列表时实现页面跳转的解决方案
方法一:使用SwiftUI原生导航机制(推荐)
这种方式更贴合SwiftUI的设计范式,将跳转逻辑交给SwiftUI统一处理,避免混合UIKit导航带来的兼容性问题:
- 修改
ContactView,添加绑定属性跟踪选中的联系人:
struct ContactView: UIViewControllerRepresentable { let viewModel: ContactsViewModel @Binding var selectedContact: Contact? // 替换为你的联系人模型类型 func makeUIViewController(context: Context) -> ContactsTableViewController { let vc = ContactsTableViewController(viewModel: viewModel) vc.tableView.delegate = context.coordinator return vc } func updateUIViewController(_ uiViewController: ContactsTableViewController, context: Context) { } }
- 更新Coordinator,选中联系人时修改绑定状态:
extension ContactView { class Coordinator: NSObject, UITableViewDelegate { var parent: ContactView init(_ parent: ContactView) { self.parent = parent } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let contact = parent.viewModel.contacts[indexPath.row] parent.selectedContact = contact tableView.deselectRow(at: indexPath, animated: true) } } func makeCoordinator() -> Coordinator { Coordinator(self) } }
- 在SwiftUI主视图中用
NavigationStack处理跳转:
如果详情页是UIKit的DetailViewController,先将其包装为UIViewControllerRepresentable:
struct DetailViewRepresentable: UIViewControllerRepresentable { let contact: Contact func makeUIViewController(context: Context) -> DetailViewController { let dependencies = DetailsViewModel.Dependencies( contacts: parent.viewModel.contacts, contactMethod: contact.contactMethod ) let viewModel = DetailsViewModel(dependencies: dependencies) return viewModel.detailViewControllerFactory(viewModel.contacts, contact.contactMethod) } func updateUIViewController(_ uiViewController: DetailViewController, context: Context) { } }
然后在主视图中配置导航:
struct MainContentView: View { @State private var selectedContact: Contact? let viewModel: ContactsViewModel var body: some View { NavigationStack { ContactView(viewModel: viewModel, selectedContact: $selectedContact) .navigationDestination(item: $selectedContact) { contact in DetailViewRepresentable(contact: contact) } } } }
方法二:直接使用UIKit导航控制器推送
如果需要保留UIKit的pushViewController逻辑,可以通过获取宿主视图控制器的导航引用实现:
- 给Coordinator添加
ContactsTableViewController的引用:
extension ContactView { class Coordinator: NSObject, UITableViewDelegate { var parent: ContactView weak var hostVC: ContactsTableViewController? // 宿主视图控制器引用 init(_ parent: ContactView) { self.parent = parent } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let contact = parent.viewModel.contacts[indexPath.row] // 创建详情视图控制器 let dependencies = DetailsViewModel.Dependencies( contacts: parent.viewModel.contacts, contactMethod: contact.contactMethod ) let viewModel = DetailsViewModel(dependencies: dependencies) let detailsViewController = viewModel.detailViewControllerFactory(viewModel.contacts, contact.contactMethod) // 获取导航控制器并推送 if let navController = hostVC?.navigationController { navController.pushViewController(detailsViewController, animated: true) } tableView.deselectRow(at: indexPath, animated: true) } } func makeCoordinator() -> Coordinator { Coordinator(self) } }
- 在
makeUIViewController中给Coordinator赋值宿主VC:
func makeUIViewController(context: Context) -> ContactsTableViewController { let vc = ContactsTableViewController(viewModel: viewModel) vc.tableView.delegate = context.coordinator context.coordinator.hostVC = vc // 传递宿主VC引用 return vc }
注意:此方法要求ContactView必须嵌入在SwiftUI的NavigationStack(iOS 15及以下用NavigationView)中,否则navigationController会返回nil。
内容的提问来源于stack exchange,提问作者onthemoon
相关产品推荐
相关产品推荐

