In this article

While introducing SwiftUI into an existing project, it may be beneficial to create a bridge between existing UIKit views and newer SwiftUI instead of rewriting the UIKit code in SwiftUI. In this example we will explore bridging a simple UITextField that may be part of a larger custom UIView for use in SwiftUI. The two key components are ensuring there is a way to observe changes in the text field as the user types and recognizing when the user submits the value.

Bridging UIKit and SwiftUI

First, create a struct that conforms to UIViewRepresentable. This is the struct that will ultimately be used in lieu of the TextField type. Inside this struct, add the necessary variables that were previously passed into the TextField. In this case, there is an @Binding text variable and an onCommit closure. Note that the following code will not compile as it stands, and it is shown in small steps to avoid confusion.

CustomTextView struct code with text and onCommit variables
CustomTextView struct code with text and onCommit variables

Add the requisite functions to connect the custom view and SwiftUI view. The makeUIView() function is where the UITextField is configured. This function is called by the system when the view is created for the first time. The updateUIView() function allows for updating the custom view upon a state change. SwiftUI calls this method when that state change occurs.

makeUIView and updateUIView functions
CustomTextView struct with text and onCommit variables and makeUIView and updateUIView functions

Create a Coordinator class that conforms to NSObject and UITextFieldDelegate. This does not have to be nested inside the custom view. It is a good practice because there may be multiple Coordinators for different UIKit views, and this method provides clean name-spacing. Two variables are needed here with the first being parent, which is the custom SwiftUI view containing the Coordinator class. 

The second variable is onCommit, a closure that executes when the user submits the value in the text field. This is to provide similar functionality to the TextField's onCommit in SwiftUI and is passed from the custom view.

Coordinator class nested inside CustomTextVIew
Coordinator class nested inside CustomTextView with an initializer and parent and onCommit variables

The necessary delegate functions must be implemented inside the Coordinator class as well. The textFieldDidChange() method allows for updating the text field when SwiftUI observes a state change. The textFieldDidEndEditing() is called when the text field resigns as first responder. This is where the onCommit closure is executed and the text from the text field is passed through.

Coordinator class nested inside CustomTextVIew with additional methods textFieldDidChange
Coordinator class nested inside CustomTextVIew with additional methods textFieldDidChange and textFieldDidEndEditing per UITextFieldDelegate

Add the makeCoordinator() function to the custom view, initialize with self as the parent and pass the onCommit closure through.

CustomTextView struct with makeCoordinator function added
CustomTextView struct with makeCoordinator function added

By the end, the CustomTextView looks like this:

Full CustomTextView struct code
Full CustomTextView struct code

Using a custom view in SwiftUI

Now this custom view is ready to be used in SwiftUI. Replace the TextField code with the CustomTextView ensuring to pass the @State variable for the text field in. Additionally, the onCommit closure can be used with trailing closure syntax.

Code to use CustomTextView on call side
Code to use CustomTextView on call side

Wrapping up

This provides a similar API to the native SwiftUI TextField view. By learning how to wrap a UIKit view for SwiftUI, you can build a bridge for many types that do not natively support SwiftUI at this time. Additionally, if you run into any corner cases with SwiftUI, you can draw on UIKit knowledge to solve these problems. 

SwiftUI has made some huge updates, and we are excited to see where it goes moving forward. Feel free to reach out directly with any questions, and make sure to follow our Application Development focus area for the latest topics and updates.