I'm currently trying, to implement a UITableViewController in a UIViewControllerRepresentable, where the contents of the cells are SwiftUI Views again. I cannot use a SwiftUI List, because I want to add an UISearchController later on.
Because I want to to be able, to put a custom SwiftUI View as the content of each cell, it's no possibility for me, to do it without SwiftUI Views inside the cells.
My current code, which isn't working looks like this:
class SearchableListCell: UITableViewCell {
let contentController: UIViewController
init(withContent content: UIViewController, reuseIdentifier: String) {
self.contentController = content
super.init(style: .default, reuseIdentifier: reuseIdentifier)
self.addSubview(self.contentController.view)
// Tried also
// self.contentView.addSubview(self.contentController.view)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
struct SearchableList: UIViewControllerRepresentable {
let data: [String]
var viewBuilder: (String) -> ContentView
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> UITableViewController {
return context.coordinator.tableViewController
}
func updateUIViewController(_ tableViewController: UITableViewController, context: Context) {
}
class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate {
var parent: SearchableList
let tableViewController = UITableViewController()
init(_ searchableList: SearchableList) {
self.parent = searchableList
super.init()
tableViewController.tableView.dataSource = self
tableViewController.tableView.delegate = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return parent.data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let string = self.parent.data[indexPath.row]
let view = parent.viewBuilder(string)
let hostingController = UIHostingController(rootView: view)
let cell = SearchableListCell(withContent: hostingController, reuseIdentifier: "cell")
// Tried it with and without this line:
tableViewController.addChild(hostingController)
return cell
}
}
}
When I run this, for example with this Preview setup:
#if DEBUG
struct SearchableList_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
SearchableList(data: ["Berlin", "Dresden", "Leipzig", "Hamburg"]) { string in
NavigationLink(destination: Text(string)) { Text(string) }
}
.navigationBarTitle("Cities")
}
}
}
#endif
I see just a TableView with 4 apparently empty cells. In the view hierarchy debugger I can see though, that each cell has indeed the NavigationLink with Text inside as a subview, it's just not visible. Therefore I think, it has to do with adding the UIHostingController as a child of the UITableViewController, but I just don't know where I should add it else.
Is there a way to do this at the moment?
UITableView
inside aUITableViewRepresentable
working because of needing aUINavigationController
subclass. If the only thing you have to gain by using SwiftUI within a UIKit table within a SwiftUI app is... forward compatibility? PreviewProvider? Well, remember, aUIViewControllerRepresentable
is considered to be merely a SwiftUI view. – NumbskullUIKit
table view, cells and all, that could be either a child view controller or a view in SwiftUI. But I was having issues making my "Edit" button triggering things in my SwiftUI model, so I'm headed down the way of using aList
- with an additional button for "Add", since I couldn't find a good way to hide it in edit mode. Could you expose your UIKit logic as delegates, using a Coordinator? – NumbskullSwiftUI
Button as a replacement for the Add button.... – Numbskull