Alex
Posted on May 22, 2023
Hello community, the other day I was trying to use Xcode playground to test some UI but the experience was not the best. Xcode was crashing constantly so I decided to try another approach.
Use the SwiftUI preview to test my UIKit Views !.
So in this tutorial we're going to learn the first steps into integrating UIKit inside SwiftUI.
Let's start!
Creating the project
First let's start Xcode and create a new project, then select iOS > App and click Next. This time select SwiftUI as the interface and give it any name you want. Finally select a place to save the files and create the project.
Creating the UIKit View
Let's create a new swift file with the name of CounterViewController.swift
. We are going to create our UIKit interface inside this file.
For simplicity, let's make a simple view that shows a label an a button.
import UIKit
final class CounterViewController: UIViewController {
private var counter = 0
private lazy var button: UIButton = {
let button = UIButton()
button.setTitle("Tap me from UIKit", for: .normal)
button.setTitleColor(.systemBlue, for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
private lazy var label: UILabel = {
let label = UILabel()
label.text = getMessage()
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
addComponents()
addHandlers()
addConstrains()
}
}
private extension CounterViewController {
func getMessage() -> String{
"UIKit Button was tapped \(counter)"
}
func addConstrains() {
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: view.topAnchor, constant: 64),
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.widthAnchor.constraint(equalToConstant: 250),
label.heightAnchor.constraint(equalToConstant: 50),
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 64),
button.heightAnchor.constraint(equalToConstant: 48),
button.widthAnchor.constraint(equalToConstant: 200),
])
}
func addComponents() {
[button, label]
.forEach { view.addSubview($0) }
}
func addHandlers() {
button.addTarget(self, action: #selector(didButtonTapped), for: .touchUpInside)
}
@objc func didButtonTapped(_ sender: UIButton) {
counter += 1
label.text = getMessage()
}
}
the above code shows a Label that will be updated once the button is pressed.
Creating the SwiftUI binding
To embed our UIKit code inside the SwiftUI we need to create a new file that contains a struct that conforms to UIViewControllerRepresentable
.
Create a new swift file called CounterView
and add the following code:
import SwiftUI
struct CounterView: UIViewControllerRepresentable {
typealias UIViewControllerType = CounterViewController
func makeUIViewController(context: Context) -> CounterViewController {
CounterViewController()
}
func updateUIViewController(_ uiViewController: CounterViewController, context: Context) {
// Update the ViewController here
}
}
This struct is the wrapper we are going to use to create our SwiftUI view.
To conform to UIViewControllerRepresentable
our structs needs three things
-
typealias UIViewControllerType
: This is a type alias for the UIKitClass, in our case is the ViewController. -
func makeUIViewController(context: Context)
: This functions is the one that will create an instance of our ViewController for SwiftUI -
func updateUIViewController(_ uiViewController: CounterViewController, context: Context)
: This function is called each time a change in our view state occurs, we can update our UIKit in this function.
Creating our View object in SwiftIU
Finally, let's create our binding view that we will use in SwiftUI.
To do so just instantiate the new View object and that's all.
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Text("SwiftUI + UIKit")
.padding(48)
.font(.title.bold())
CounterView(labelText: $label)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Xcode live previewing the UIKit component, you can click it on the button and it will work!.
Now you can make changes to your UIKit code and see a live update on the SwiftUI preview.
Conclusion
In this first tutorial we were able to embed a UIKit view controller inside a SwiftUI View and we were able to preview our work inside the live preview. This first attempt show us how easy is to create interoperability between SwiftUI and UIKit.
In coming tutorial, we will be adding bidirectional communication with @Binding
and @State
.
Thank you for reading.
Posted on May 22, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.