SwiftUI:如何从UIViewRepresentable的UITableView导航至View
你遇到的核心问题是:在UIViewRepresentable封装的UITableView的Coordinator里,无法直接访问到NavigationView对应的UINavigationController。下面提供两种可行的解决方案,分别适配SwiftUI风格和UIKit风格的跳转需求:
方案一:用SwiftUI原生NavigationLink(推荐)
这种方式更贴合SwiftUI的状态驱动设计,通过在TableView中定义选中回调,在ContentView里用NavigationLink完成跳转:
步骤1:给TableView添加选中回调闭包
修改TableView结构体,添加一个@escaping闭包来传递选中事件:
struct TableView: UIViewRepresentable { @State var rows = ["London", "Paris", "Oslo"] // 新增:选中行的回调闭包 let onRowSelected: (Int) -> Void func makeUIView(context: Context) -> UITableView { let table = UITableView() table.register(UITableViewCell.self, forCellReuseIdentifier: "Cell") table.dataSource = context.coordinator table.delegate = context.coordinator return table } func updateUIView(_ uiView: UITableView, context: Context) {} func makeCoordinator() -> Coordinator { // 初始化Coordinator时传递回调闭包 return Coordinator(rows: $rows, onRowSelected: onRowSelected) } class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate { @Binding var rows: [String] let onRowSelected: (Int) -> Void init(rows: Binding<[String]>, onRowSelected: @escaping (Int) -> Void) { self._rows = rows self.onRowSelected = onRowSelected } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.rows.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") cell?.textLabel?.text = self.rows[indexPath.row] return cell! } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // 触发回调,传递选中的行索引 onRowSelected(indexPath.row) } // 保留你的左右滑操作代码... func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let add = UIContextualAction(style: .normal,title: "Add") { (action, view, success) in success(true) } add.backgroundColor = .gray return UISwipeActionsConfiguration(actions: [add]) } func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let remove = UIContextualAction(style: .normal,title: "Remove") { (action, view, success) in success(true) } remove.backgroundColor = .red let edit = UIContextualAction(style: .normal,title: "Edit") { (action, view, success) in success(true) } edit.backgroundColor = .gray let color = UIContextualAction(style: .normal, title: "Color") { (action, view, success) in success(true) } return UISwipeActionsConfiguration(actions: [remove, edit, color]) } } }
步骤2:在ContentView中使用NavigationLink响应跳转
通过状态变量控制隐藏的NavigationLink,实现选中行后的跳转:
struct ContentView: View { // 存储选中的行索引,控制导航状态 @State private var selectedRowIndex: Int? = nil var body: some View { NavigationView { VStack { HStack { Text("Some other Views") } // 传递选中回调 TableView(onRowSelected: { index in selectedRowIndex = index }) // 隐藏的NavigationLink,通过状态触发跳转 NavigationLink( destination: Text("Destination for \(rows[selectedRowIndex ?? 0])"), tag: selectedRowIndex, selection: $selectedRowIndex ) { EmptyView() } .hidden() } .navigationTitle("Cities") } } // 复用TableView的数据源,或者直接传递也行 private let rows = ["London", "Paris", "Oslo"] }
方案二:直接获取UINavigationController(UIKit风格)
如果你更习惯用UIKit的pushViewController方式,可以通过UIView的扩展获取父视图控制器,进而拿到UINavigationController:
步骤1:添加UIView扩展获取父ViewController
extension UIView { // 获取当前视图所在的父ViewController var parentViewController: UIViewController? { var currentResponder: UIResponder? = self while currentResponder != nil { currentResponder = currentResponder?.next if let vc = currentResponder as? UIViewController { return vc } } return nil } }
步骤2:在Coordinator的didSelectRowAt中跳转
修改Coordinator中的didSelectRowAt方法:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let destination = Text("Destination for \(rows[indexPath.row])") let host = UIHostingController(rootView: destination) // 获取当前NavigationController并跳转 if let navController = tableView.parentViewController?.navigationController { navController.pushViewController(host, animated: true) } }
这种方式不需要修改TableView的外部接口,但依赖UIKit的视图层级,灵活性不如方案一。
内容的提问来源于stack exchange,提问作者mahan
相关产品推荐
相关产品推荐

