2

I'm working on a legacy app and trying to embed a swiftUI view inside a UIKit UITableView. The SwiftUI view is a LazyHGrid with a number of items based on a user's number of accounts. The idea is to display the first 1-3 items (if there are any), and a "More" button, which, when tapped, displays the rest of the items.

The SwiftUI piece is working correctly, and initially the tableView displays it correctly, like so: three tiles working correctly. However, when I tap the "More" button, the other items pop in, but the row height in the table doesn't adjust, so they just overlap the other content in the table, like so: tiles overlapping other content.

Here's the host function that controls the swiftUI view:

func host(_ view: Content, parent: UIViewController) {
        hostingController.rootView = view
        hostingController.view.invalidateIntrinsicContentSize()
        
        let requiresControllerMove = hostingController.parent != parent
        
        if requiresControllerMove {
            // remove old parent if exists
            removeHostingControllerFromParent()
            parent.addChild(hostingController)
        }
        
        if !contentView.subviews.contains(hostingController.view) {
            contentView.addSubview(hostingController.view)
            
            hostingController.view.translatesAutoresizingMaskIntoConstraints = false
            hostingController.view.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
            hostingController.view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
            hostingController.view.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
            hostingController.view.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
        }
                
        if requiresControllerMove {
            hostingController.didMove(toParent: parent)
        }
    }

I register the cell in the viewDidLoad in the UIKit controller:

self.tableView.register(SwiftUIHostTableViewCell<BillingTileGridView>.self, forCellReuseIdentifier: "BillingTileGridViewCell")

(This code was already present in the viewDidLoad):

  self.tableView.estimatedRowHeight = 60
  self.tableView.rowHeight = UITableView.automaticDimension

And then I create the cell like so in the tableView cellForRowAt function:


if let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseID, for: indexPath) as? SwiftUIHostTableViewCell<BillingTileGridView> {
                let view = BillingTileGridView(viewModel: BillingTileGridViewModel(), adjustHeight: {
                })
                cell.host(view, parent: self)
                return cell
            }

I tried using a callback to re-load the table height for the button action, like this:

                let view = BillingTileGridView(viewModel: BillingTileGridViewModel(), adjustHeight: {
                    tableView.beginUpdates()
                    tableView.endUpdates()
                })

like I'd seen in questions like this one, Swift: How to reload row height in UITableViewCell without reloading data, but it didn't seem to do anything. Do I just need to calculate the height manually based on how many rows I have, and set the height explicitly to that?

KDBartleby
  • 23
  • 6

0 Answers0