Chapter 23
Integrating UIKit with SwiftUI Using UIViewRepresentable

In the previous chapter, we addressed a common question about Core Data and SwiftUI. The other common question is how to work with UIKit views in SwiftUI projects. In this chapter, you will learn this technique by integrating a UISearchBar in the Todo app.

If you are new to UIKit, UISearchBar is a built-in component of the framework that allows developers to present a search bar for data search. Figure 1 shows you the standard search bar in iOS. For SwiftUI, however, it doesn't come with this standard UI component. To implement a search bar in a SwiftUI project (say, our ToDo app), one approach is to make use of the UISearchBar component in UIKit.

So, how can we interface with UIKit views or controllers in SwiftUI?

For the purpose of backward compatibility, Apple introduced a couple of new protocols, namely UIViewRepresentable and UIViewControllerRepresentable in the iOS SDK. With these protocols, you can wrap a UIKit view (or view controller) and make it available to your SwiftUI project.

To see how it works, we will enhance our Todo app with a search function. We will add a search bar right below the app title and let users filter the to-do items by entering a search term.

Figure 1. Adding a search bar in the ToDo app
Figure 1. Adding a search bar in the ToDo app

To get started, please download the ToDo project. We will build on top of the existing project. In case you haven't read chapter 22, I recommend you to check it out first. This will help you better understand the topic we are going to discuss below, especially you have no idea about Core Data.

Understanding UIViewRepresentable

To use a UIKit view in SwiftUI, you can wrap the view with the UIViewRepresentable protocol. Basically, you just need to create a struct in SwiftUI that adopts the protocol to create and manage a UIView object. Here is the skeleton of the custom wrapper for a UIKit view:

struct CustomView: UIViewRepresentable {

    func makeUIView(context: Context) -> some UIView {
        // Return the UIView object
    }

    func updateUIView(_ uiView: some UIView, context: Context) {
        // Update the view
    }
}

In the actual implementation, you replace some UIView with the UIKit view you want to wrap. Let's say, we want to use UISearchBar in UIKit. The code can be written like this:

struct SearchBar: UIViewRepresentable {

    func makeUIView(context: Context) -> UISearchBar {

        return UISearchBar()
    }

    func updateUIView(_ uiView: UISearchBar, context: Context) {

        // Update the view
    }
}

In the makeUIView method, we return an instance of UISearchBar. This is how you wrap a UIKit view and make it available to SwiftUI. To use the SearchBar, you can treat like any SwiftUI view and create it like this:

struct ContentView: View {
    var body: some View {
        SearchBar()
    }
}

To access the full content and the complete source code, please get your copy at https://www.appcoda.com/swiftui.

results matching ""

    No results matching ""