How can I use a SwiftUI view struct in place of a traditional cell and xib in a UITableViewController?
import UIKit
import SwiftUI
class MasterViewController: UITableViewController {
var detailViewController: DetailViewController? = nil
var objects = [Any]()
// MARK: - View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
navigationItem.title = "Table View"
//...
}
// MARK: - Table View Methods
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(MySwiftUIView())
// ...
return cell
}
} ...
The issue is obvious in that UIHostedController SwiftUI view is not a table cell, but how could I use it like one?
Open Xcode and select Create a new Xcode project. And then fill in the details for the new project, let's name the app “RestaurantMenu” and make sure you've selected SwiftUI for the User Interface. And click Next. And then choose your preferred directory and click on Create to create your new Project.
Thanks for answering your own question here. Your solution helped me make a generic HostingTableViewCell class. I'll post it here if anyone finds this question on Google like I did.
import SwiftUI
class HostingTableViewCell<Content: View>: UITableViewCell {
private weak var controller: UIHostingController<Content>?
func host(_ view: Content, parent: UIViewController) {
if let controller = controller {
controller.rootView = view
controller.view.layoutIfNeeded()
} else {
let swiftUICellViewController = UIHostingController(rootView: view)
controller = swiftUICellViewController
swiftUICellViewController.view.backgroundColor = .clear
layoutIfNeeded()
parent.addChild(swiftUICellViewController)
contentView.addSubview(swiftUICellViewController.view)
swiftUICellViewController.view.translatesAutoresizingMaskIntoConstraints = false
contentView.addConstraint(NSLayoutConstraint(item: swiftUICellViewController.view!, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.equal, toItem: contentView, attribute: NSLayoutConstraint.Attribute.leading, multiplier: 1.0, constant: 0.0))
contentView.addConstraint(NSLayoutConstraint(item: swiftUICellViewController.view!, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: contentView, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1.0, constant: 0.0))
contentView.addConstraint(NSLayoutConstraint(item: swiftUICellViewController.view!, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: contentView, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1.0, constant: 0.0))
contentView.addConstraint(NSLayoutConstraint(item: swiftUICellViewController.view!, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: contentView, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1.0, constant: 0.0))
swiftUICellViewController.didMove(toParent: parent)
swiftUICellViewController.view.layoutIfNeeded()
}
}
}
In your UITableViewController:
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(HostingTableViewCell<Text>.self, forCellReuseIdentifier: "textCell")
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "textCell") as! HostingTableViewCell<Text>
cell.host(Text("Yay!"), parent: self)
return cell
}
Might turn this into a package if people seem to use it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With