Search bar not updating text in UI

I have implemented a custom NavigationView with a search bar in SwiftUI.

The SearchResultsContent doesn’t update properly though. I can’t seem to figure out why.
I’ve done all the UISearchResultsUpdating related things, but that doesn’t fix the problem.

Code Block Swift
struct SearchBarNavigationView<SearchResultsContent: View, Content: View>: UIViewControllerRepresentable {
class Coordinator: NSObject, UISearchResultsUpdating {
private let parent: SearchBarNavigationView
init(_ parent: SearchBarNavigationView) {
self.parent = parent
}
func updateSearchResults(for searchController: UISearchController) {
guard let searchText = searchController.searchBar.text else { return }
DispatchQueue.main.async { self.parent.text = searchText }
}
}
@Binding private var text: String
private let searchResultsContent: SearchResultsContent
private let content: Content
init(text: Binding<String>, @ViewBuilder searchResultsContent: () -> SearchResultsContent, @ViewBuilder content: () -> Content) {
_text = text
self.searchResultsContent = searchResultsContent()
self.content = content()
}
func makeUIViewController(context: Context) -> UINavigationController {
let rootViewController = UIHostingController(rootView: content)
let navigationController = UINavigationController(rootViewController: rootViewController)
navigationController.navigationBar.prefersLargeTitles = true
let searchResultsController = UIHostingController(rootView: searchResultsContent)
let searchController = UISearchController(searchResultsController: searchResultsController)
searchController.searchResultsUpdater = context.coordinator
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.autocapitalizationType = .none
navigationController.navigationBar.topItem?.searchController = searchController
return navigationController
}
func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {
if let searchResultsController = uiViewController.navigationBar.topItem?.searchController?.searchResultsController as? UIHostingController<SearchResultsContent> {
searchResultsController.rootView = searchResultsContent
searchResultsController.view.setNeedsDisplay()
}
if let rootViewController = uiViewController.topViewController as? UIHostingController<Content> {
rootViewController.rootView = content
rootViewController.view.setNeedsDisplay()
}
uiViewController.navigationBar.topItem?.searchController?.searchBar.text = text
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
}

Implementation in View
Code Block Swift
SearchBarNavigationView(text: $searchText) {
Text(searchText) // doesn’t change whilst typing
} content: {
List(0 ..< 20) {
Text("Row \($0)")
}
}
.ignoresSafeArea()
.onChange(of: searchText) { value in
print(value) // works correctly
}


Answered by BabyJ in 652503022
It turns out I needed to change some code in the updateUIViewController(_:context:) method to reload the SearchResultsContent
Code Block Swift
if let searchResultsController = uiViewController.navigationBar.topItem?.searchController?.searchResultsController as? UIHostingController<SearchResultsContent> {
searchResultsController.rootView = searchResultsContent
searchResultsController.view.setNeedsDisplay()
}

With these two lines:
Code Block
private let searchResultsContent: SearchResultsContent
private let content: Content

you keep the result View which is built on initialization.

Try keeping the closures, and invoke them when needed:
Code Block
private let searchResultsContent: ()->SearchResultsContent
private let content: ()->Content


Accepted Answer
It turns out I needed to change some code in the updateUIViewController(_:context:) method to reload the SearchResultsContent
Code Block Swift
if let searchResultsController = uiViewController.navigationBar.topItem?.searchController?.searchResultsController as? UIHostingController<SearchResultsContent> {
searchResultsController.rootView = searchResultsContent
searchResultsController.view.setNeedsDisplay()
}

Search bar not updating text in UI
 
 
Q