Search code examples
iosswiftuitableviewswiftuiuikit

SwiftUI - Navigate from UITableView (UIViewRepresentable) to View


I have a NavigationView that contains a UItableView at the bottom. At the top, there are some more views. I am using UItableView because I need both of its trailing and leading swipe actions.

Since the table view is a subview of NavigationView, is there any way to access it in UITableView, in its didSelectRowAt method?

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let destination = Text("Destination")
        let host = UIHostingController(rootView: destination)
        
        //TODO: - Navigate to Destination
        //navigationController.pushViewController(host, animated: true)
    }

UITableView

struct TableView: UIViewRepresentable {
    @State var rows = ["London", "Paris", "Oslo"]
    
    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 {
        return Coordinator(rows: $rows)
    }
    
    class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate {
        @Binding var rows: [String]
        
        init(rows: Binding<[String]>) {
            self._rows = rows
        }
        
        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) {
            let destination = Text("Destination")
            let host = UIHostingController(rootView: destination)
            
            //TODO: - Navigate to Destination
            //navigationController.pushViewController(host, animated: true)
        }
        
        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])
        }
    }
}

View that contains the tableView

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                HStack {
                    Text("Some other Views")
                }
                TableView()
            }
        }
    }
}

Solution

  • Using this way or other way, you can get didSelectRowAt method

    Tableview

    struct TableView: UIViewRepresentable {
        
        var completionHandler:((String) -> Void) = {_ in }
        
        @State var rows = ["London", "Paris", "Oslo"]
        
        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 {
            //return Coordinator(rows: $rows)
            return Coordinator(self)
        }
        
        class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate {
            //@Binding var rows: [String]
            
            @State var parent: TableView
            
            init(_ parent: TableView){
                self.parent = parent
            }
            
            /*
            init(rows: Binding<[String]>) {
                self._rows = rows
            }*/
            
            func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                return self.parent.rows.count
            }
            
            func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
                cell?.textLabel?.text =  self.parent.rows[indexPath.row]
                return cell!
            }
            
            func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
                self.parent.completionHandler(self.parent.rows[indexPath.row])
                //let host = UIHostingController(rootView: destination)
                
                //TODO: - Navigate to Destination
                //navigationController.pushViewController(host, animated: true)
            }
            
            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])
            }
        }
    }
    

    ContentView

    struct ContentView: View {
    
    @State var selectedString: String = ""
    @State var isPresent: Bool = false
    var body: some View {
        NavigationView {
            VStack {
                HStack {
                    Text("Some other Views")
                }
    TableView(completionHandler: { (s) in
                 self.selectedString = s
                 self.isPresent = true
                 
                }, rows: ["A","B","C","D"])
                
                NavigationLink(destination: Text(self.selectedString), isActive: $isPresent) {
                    EmptyView()
                }
                /*TableView(completionHandler: { str in
                    self.selectedString = str
                    self.isPresent = true
                }, rows: ["A","B","C","D"])*/
            }
            
            .sheet(isPresented: self.$isPresent) {
                Text(self.selectedString)
            }
        }
    }
    }