tvOS UISearchController in SwiftUI

I have been struggling to get a functional UISearchController in a SwiftUI app, under a tab bar. I've scoured the web and documentation, and managed to get something almost there, however the keyboard on the search view does not respond to left and right controls. I've seen a post on StackExchange where someone has a similar issue, but no solution.

Can anyone help to show how to make a functional search view in a SwiftUI app on tvOS 13 ?

One thing to note, while working through the views, I discovered a bug in USearchView which doesn't set a horizontal constraint for the keyboard area in one of its' inner views. I include a fix for that which adds in the constraint if one can't be found.

I've attached the full source, just add to an empty tvOS SwiftUI project (and remove AppDelegate and ContentView)



The UISearchView HostingView:
Code Block swift
struct PageView<Page: View>: View {
    var viewController: UIHostingController<Page>
    @ObservedObject var state: SearchState
    init(_ resultsView: Page, state: SearchState) {
        self.viewController = UIHostingController(rootView: resultsView)
        self.state = state
    }
    var body: some View {
        PageViewController(controller: viewController, state: state)
    }
}
struct PageViewController: UIViewControllerRepresentable {
    var controller: UIViewController
    @ObservedObject var state: SearchState
    func makeUIViewController(context: Context) -> UINavigationController {
        let searchController = UISearchController(searchResultsController: controller)
        searchController.searchResultsUpdater = state
        searchController.searchBar.placeholder = NSLocalizedString("Enter search (e.g. Shawshank)", comment: "")
        let searchContainer = UISearchContainerViewController(searchController: searchController)
        searchContainer.title = NSLocalizedString("Search", comment: "")
        let searchNavigationController = UINavigationController(rootViewController: searchContainer)
        return searchNavigationController
    }
    func updateUIViewController(_ searchContainer: UINavigationController, context: Context) {
        if searchContainer.children.count > 0,
            let searchController = (searchContainer.children[0] as? UISearchContainerViewController)?.searchController,
            let searchControllerView = searchController.view,
            searchController.children.count > 1,
            let uiKBFocusView = searchController.children[1].view,
            !searchControllerView.constraints.reduce(false, {$0 || ($1.firstAttribute == NSLayoutConstraint.Attribute.centerX) }){
            let horizontalConstraint = NSLayoutConstraint(item: uiKBFocusView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: searchControllerView, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0)
searchControllerView.addConstraints([horizontalConstraint])
        }
    }
}


The Search State and results view
Code Block swift
class SearchState: NSObject, ObservableObject, UISearchResultsUpdating {
    @Published var text: String = ""
    
    func updateSearchResults(for searchController: UISearchController) {
        let searchBar = searchController.searchBar
        self.text = searchBar.text ?? ""
    }
}



Replies

Hi did you find the solution? I'm facing the same issues using SwiftUI

what I found so far: On tvOS, start with a UISearchContainerViewController to manage the presentation of the search controller. See UIKit Catalog (tvOS): Creating and Customizing UIKit Controls to learn how to implement a search controller embedded inside a UISearchContainerViewController object. link: https://developer.apple.com/documentation/uikit/uisearchcontroller

so we should use UISearchContainerViewController instead of using SearchViewController