Sizing SwiftUI in UIKit

September 23, 2025

SwiftUI provides us a nice way of integrating SwiftUI into UIKit — UIHostingConfiguration:

let config = UIHostingConfiguration {
    Text("Hello world!")
}

We can turn this into a UIView like so:

let contentView: (UIView & UIContentView) = config.makeContentView()

We can then apply constraints:

addSubview(contentView)
contentView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([ ... ])

But here is the thing — if the SwiftUI view resizes internally, our constraints won't be invalidated.

The missing callback

I found out through experimenation, that we can leverage onGeometryChange as a callback into the UIKit world:

UIHostingConfiguration {
    VStack(spacing: .zero) {
        content
            .onGeometryChange(for: CGFloat.self) { g in
                g.size.height
            } action: { [weak self] newHeight in
                // Example: update UIKit based constraints here...
            }
        Spacer(minLength: .zero)
    }
}

This is really nice because onGeometryChange triggers in the same layout pass — which means we can resize our UIKit constraints in the same layout pass as SwiftUI itself. There’s no need to schedule the UIKit layout pass on a future run loop iteration.

Note: the tricky part is that the SwiftUI UIHostingConfiguration needs enough space to grow — you might need to give it a large height that exceeds your HostingView’s bounds, then manually adjust the height of your HostingView based on the new size.

Another option is to use UIHostingController, which has options for its constraints to dynamically resize — although this tends to be more expensive.