You are currently viewing How to Use UIHostingConfiguration to Integrate SwiftUI Views into UIKit Apps

How to Use UIHostingConfiguration to Integrate SwiftUI Views into UIKit Apps

Since the release of SwiftUI in 2019, Apple has been striving to enhance the interoperability between SwiftUI and UIKit. In iOS 16, Apple introduced UIHostingConfiguration, which is a powerful feature that enables developers to use SwiftUI views as UITableView or UICollectionView cells.

Recently, I came across an article that showed me another use case for UIHostingConfiguration that I was not aware of. It turns out that UIHostingConfiguration allows us to create a SwiftUI view that can be used in UIKit apps. I am extremely excited about this discovery and would like to share the details with you in this article.


How Does It Work

The concept behind is actually pretty straightforward. All we need to do is convert the SwiftUI view into a UIView. Let me show you how:

let config = UIHostingConfiguration {
    Text("This is a SwiftUI view!")
}
let subview = config.makeContentView()
view.addSubview(subview)

If you take a look at the code above, you’ll notice that the makeContentView() method is where the magic happens. This method takes the SwiftUI view and converts it into a UIView. This means that we can now use the converted view just like any other UIView.

What’s great about this approach is that it removes the need to use UIHostingController for simple UIs, while allowing us to easily access all the cool SwiftUI features that are not available in UIKit.


The Use Case Example

Let’s put what we just learned into practice by creating the following effect in a UIKit app.

Using UIHostingConfiguration to Integrate SwiftUI Views into UIKit Apps
String with hyperlinks that animates

Notice that the checkbox is created using a UIButton, while the agreement string is a SwiftUI view. The reason why I am doing this is to demonstrate how a UIKit component can interact with a SwiftUI view. In most cases, it is always better to include the checkbox as part of the SwiftUI view.

Firstly, let’s create the SwiftUI view and name it AgreementView.

struct AgreementView: View {
    
    class ViewState: ObservableObject {
        @Published var isChecked = false
    }
    
    /// ObservableObject to keep track of the current check status
    @ObservedObject var currentViewState = ViewState()
    
    @State private var fontSize = 16.0
    @State private var isBold = false
    
    var body: some View {
        Text("I have read and agree to Apple's [User Agreement](https://www.apple.com/legal/internet-services/itunes/dev/stdeula/) and [Privacy Policy](https://www.apple.com/legal/privacy/en-ww/)")
            .font(.system(size: fontSize))
            .bold(isBold)
            .onReceive(currentViewState.$isChecked) { checked in
                // Animate based on the `isCheck` state
                withAnimation(.spring(response: 0.5, dampingFraction: 0.5, blendDuration: 1)) {
                    fontSize = checked ? 18.0 : 16.0
                    isBold = checked
                }
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
    }
    
    func setIsChecked(_ isChecked: Bool) {
        // Update current `isCheck` state
        currentViewState.isChecked = isChecked
    }
}

There are a few things in the above code that are worth mentioning.

First, we use the SwiftUI markdown feature introduced in iOS 15 to create an agreement string that contains a hyperlink.

Then, we use the onReceive modifier to update the font size and font weight of the text when the checkbox is tapped, so that we can get the cool animation as shown in the animated GIF.

Lastly, notice that there is a method called setIsChecked() that we will use later on to update the isChecked state of the AgreementView.

With the AgreementView in place, integrating it with a view controller is straightforward.

let agreementView = AgreementView()
checkbox.switchButtonValueDidChanged = { (_, isSelected) in
    // Update `agreementView` check status
    agreementView.setIsChecked(isSelected)
}

// Convert `agreementView` to UIView
let config = UIHostingConfiguration {
    agreementView
}
let subview = config.makeContentView()

// Add `agreementView` into a container view
view.addSubview(subview)

We can use the makeContentView() method to convert the SwiftUI view into a UIView and add it as a subview to the view controller. After that, we can use the checkbox’s switchButtonValueDidChanged callback that triggers every time a user taps on it to update the AgreementView‘s isChecked state.

For those interested in trying this themselves, the full sample code is available on GitHub.


Wrapping Up

With all this being said, it is important to note that UIHostingConfiguration should not be seen as a replacement for UIHostingController. Instead, UIHostingConfiguration is best used for displaying simple SwiftUI views within a view controller, while for more complex views, it is still better to use UIHostingController.

As an iOS developer who primarily uses UIKit, UIHostingConfiguration is definitely one of my favorite interoperability features. I have written several articles covering this topic in detail, so be sure to check them out if you’re interested.


I hope you enjoy reading this article, if you do, you can follow me on Twitter or LinkedIn and subscribe to my newsletter to stay up-to-date with my latest iOS development-related articles.

Thanks for reading! 👨🏻‍💻


👋🏻 Hey!

While you’re still here, why not check out some of my favorite Mac tools on Setapp? They will definitely help improve your day-to-day productivity. Additionally, doing so will also help support my work.

  • Bartender: Superpower your menu bar and take full control over your menu bar items.
  • CleanShot X: The best screen capture app I’ve ever used.
  • PixelSnap: Measure on-screen elements with ease and precision.
  • iStat Menus: Track CPU, GPU, sensors, and more, all in one convenient tool.