UISearchController how to activate from SwiftUI
To activate a UISearchBar
(which is what you're using), just do:
searchController.searchBar.becomeFirstResponder()
(from this answer)
Now all we need to do is reference searchController.searchBar
from the SwiftUI view. First, add a function to your SearchBar
class.
class SearchBar: NSObject, ObservableObject {
@Published var text: String = ""
let searchController: UISearchController = UISearchController(searchResultsController: nil)
override init() {
super.init()
self.searchController.obscuresBackgroundDuringPresentation = false
self.searchController.searchResultsUpdater = self
}
/// add this function
func activate() {
searchController.searchBar.becomeFirstResponder()
}
}
Then, just call it. I think this is better than setting a @State
, but if you require that, let me know and I'll edit my answer.
struct ContentView: View {
@StateObject var searchBar = SearchBar()
var body: some View {
NavigationView {
Button(action: {
searchBar.activate() /// activate the search bar
}) {
Text("Activate search bar")
}
.modifier(SearchBarModifier(searchBar: searchBar))
.navigationTitle("Navigation View")
}
}
}
Result:
How to incorporate a UISearchController into SwiftUI NavigationView by using UINavigationController's searchController property?
I was able to get this working without using UINavigationController
in a UIViewControllerRepresentable
. In fact, in my own experiments in answering this question I found that to be a quite error prone method when views get updated.
The technique here is similar to that question: Use a dummy UIViewController
in order to configure your navigation.
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination: Text("Bye")) {
Text("Hi")
.background(SearchControllerSetup())
.navigationBarTitle("Hello", displayMode: .inline)
}
}
}
}
struct SearchControllerSetup: UIViewControllerRepresentable {
typealias UIViewControllerType = UIViewController
func makeCoordinator() -> SearchCoordinator {
return SearchCoordinator()
}
func makeUIViewController(context: Context) -> UIViewController {
return UIViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
// This will be called multiple times, including during the push of a new view controller
if let vc = uiViewController.parent {
vc.navigationItem.searchController = context.coordinator.search
}
}
}
class SearchCoordinator: NSObject {
let updater = SearchResultsUpdater()
lazy var search: UISearchController = {
let search = UISearchController(searchResultsController: nil)
search.searchResultsUpdater = self.updater
search.obscuresBackgroundDuringPresentation = false
search.searchBar.placeholder = "Type something"
return search
}()
}
class SearchResultsUpdater: NSObject, UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
guard let text = searchController.searchBar.text else { return }
print(text)
}
}
Results:
How we can adding a search bar with side bar icon to the navigation view?
As I mentioned in comments this is not possible in SwiftUI (2.0) yet. What you can do is integrating with UIKit.
Integrate with UIKit
class UIKitSearchBar: NSObject, ObservableObject {
@Published var text: String = ""
let searchController = UISearchController(searchResultsController: nil)
override init() {
super.init()
self.searchController.obscuresBackgroundDuringPresentation = false
self.searchController.definesPresentationContext = true
self.searchController.searchResultsUpdater = self
}
}
extension UIKitSearchBar: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
// Publish search bar text changes.
if let searchBarText = searchController.searchBar.text {
self.text = searchBarText
}
}
}
struct SearchBarModifier: ViewModifier {
let searchBar: UIKitSearchBar
func body(content: Content) -> some View {
content
.overlay(
ViewControllerResolver { viewController in
viewController.navigationItem.searchController = self.searchBar.searchController
}
.frame(width: 0, height: 0)
)
}
}
extension View {
func add(_ searchBar: UIKitSearchBar) -> some View {
return self.modifier(SearchBarModifier(searchBar: searchBar))
}
}
final class ViewControllerResolver: UIViewControllerRepresentable {
let onResolve: (UIViewController) -> Void
init(onResolve: @escaping (UIViewController) -> Void) {
self.onResolve = onResolve
}
func makeUIViewController(context: Context) -> ParentResolverViewController {
ParentResolverViewController(onResolve: onResolve)
}
func updateUIViewController(_ uiViewController: ParentResolverViewController, context: Context) { }
}
class ParentResolverViewController: UIViewController {
let onResolve: (UIViewController) -> Void
init(onResolve: @escaping (UIViewController) -> Void) {
self.onResolve = onResolve
super.init(nibName: nil, bundle: nil)
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func didMove(toParent parent: UIViewController?) {
super.didMove(toParent: parent)
if let parent = parent {
onResolve(parent)
}
}
}
Usage
struct Example: View {
@StateObject var searchBar = UIKitSearchBar()
var body: some View {
NavigationView {
Text("Example")
.add(searchBar)
.navigationTitle("Example")
}
}
}
In my own project I am using computed property to filter stuff, it can be helpful for you too. Here is my code:
var filteredExams: [Exam] {
examModel.exams.filter({ searchBar.text.isEmpty || $0.examName.localizedStandardContains(searchBar.text)})
}
Screenshot
Related Topics
Closures Return Value (Previously Completionblock)
How to Add Custom Init for String Extension
Need Detailed Explanation for Memoize Implementation in Swift (Wwdc 14, Session 404)
How to Get the Unicode Codepoint Represented by an Integer in Swift
Nsurlsessiondatadelegate Method Didreceivedata and Others Are Not Called
Passing and Storing Closures/Callbacks in Swift
Swift Combine: Using Timer Publisher in an Observable Object
Realmswift + Multiple Predicate
Convert to Latest Swift Syntax' Breaks the Build Even When There Are No Changes
How to Integrate Uisearchcontroller with Swiftui
How to Set Interactive Push Notifications on iOS8
Swiftui MACos Commands (Menu Bar) and View
How to Retrieve All Contacts Using Cncontact.Predicateforcontacts
How Do We Implement Wait/Notify in Swift
How to I Access Argv and Argc in Swift
Uicollectionview Autosize and Dynamic Number of Rows