Set action to cancel button inside an uisearchController - swift

let searchController = UISearchController(searchResultsController: nil)
uiView.addSubview(searchController.searchBar)
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
How can i add action to the cancel button of the search bar. i want to reload table's data once the user press the cancel button.

You need to set the delegate of the UISearchController like so:
searchController.searchBar.delegate = self;
Then you can add the method below to your code (which is triggered when the cancel button is pressed):
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
}

Related

Linking a search bar to a collection view

I have a collection view with cells, I've added the search bar into the navigation bar but I'm having trouble being able to set it so that when I enter text in the search bar it filters the cells to only leave the ones that match the text in the search bar can anyone help me
I know the normal way of using the search bar is with a table view but I'm trying to do it with collection views
Hope below piece of code helps,
class SearchCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Enter text"
searchController.isActive = true
navigationItem.searchController = searchController
definesPresentationContext = true
}
}
extension SearchCollectionViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
let searchText = searchController.searchBar.text
//Here you can update/filter cells in collection view
}
}

How to redraw NavigationBar to show SearchController on button press?

I am using a button in my navigationItem.title, which when pressed, I would like to display the navigationItem.searchController.
When cancel is pressed on the search bar, I would like to dismiss the search controller, and redraw the navigation bar.
var universalSearchController = UISearchController(searchResultsController: nil)
override func viewWillAppear(_ animated: Bool) {
// Set search delegate and who will be updating the results
universalSearchController.searchBar.delegate = self
universalSearchController.searchResultsUpdater = self
universalSearchController.delegate = self
definesPresentationContext = true
titleButton.addTarget(self, action: #selector(titleButtonTapped), for: .touchUpInside)
}
Basically everything I have tried is all in here:
#objc func titleButtonTapped() {
// Set the searchController
navigationItem.searchController = universalSearchController
// Below are attempts at redrawing the navigation bar
universalSearchController.searchBar.becomeFirstResponder()
universalSearchController.searchBar.isHidden = false
// Try to refresh by showing/hiding
self.navigationController?.isNavigationBarHidden = true
self.navigationController?.isNavigationBarHidden = false
universalSearchController.view.setNeedsLayout()
universalSearchController.view.layoutIfNeeded()
universalSearchController.view.setNeedsDisplay()
universalSearchController.view.reloadInputViews()
view.setNeedsDisplay()
view.setNeedsLayout()
view.layoutIfNeeded()
view.reloadInputViews()
navigationController!.navigationBar.setNeedsDisplay()
navigationController!.navigationBar.setNeedsLayout()
navigationController!.navigationBar.layoutIfNeeded()
navigationController!.navigationBar.reloadInputViews()
navigationController!.view.setNeedsDisplay()
navigationController!.view.setNeedsLayout()
navigationController!.view.layoutIfNeeded()
navigationController!.view.reloadInputViews()
}
For hiding the searchController:
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
// Get rid of the searchController
navigationItem.searchController = nil
universalSearchController.searchBar.isHidden = true
universalSearchController.searchBar.resignFirstResponder()
// Try to refresh by showing/hiding
self.navigationController?.isNavigationBarHidden = true
self.navigationController?.isNavigationBarHidden = false
navigationController?.navigationBar.backgroundColor = .red
universalSearchController.view.setNeedsLayout()
universalSearchController.view.layoutIfNeeded()
universalSearchController.view.setNeedsDisplay()
universalSearchController.view.reloadInputViews()
view.setNeedsDisplay()
view.setNeedsLayout()
view.layoutIfNeeded()
view.reloadInputViews()
navigationController!.navigationBar.setNeedsDisplay()
navigationController!.navigationBar.setNeedsLayout()
navigationController!.navigationBar.layoutIfNeeded()
navigationController!.navigationBar.reloadInputViews()
}
The weird thing is that if I present a view over my current table view, and then dismiss it, the navigation bar is there.

UISeachController Delegate methods not called, searchbar can't become first responder

I'm having some difficulty getting the searchbar in my searchcontroller to become firstResponder. I've noticed the delegate methods are not being called, but the searchbar works as intended when I'm typing to filter a list of users.
Definition of searchcontroller:
lazy var searchController: UISearchController = {
let searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search"
return searchController
}()
Setting it up:
private func setupSearchController() {
self.navigationItem.searchController = searchController
searchController.definesPresentationContext = true
searchController.delegate = self
searchController.isActive = true
searchController.searchBar.delegate = self
searchController.searchBar.becomeFirstResponder()
}
I tried this suggestion from another SO question but the delegate method isn't being called:
func didPresentSearchController(searchController: UISearchController) {
UIView.animate(withDuration: 0.1, animations: { () -> Void in }) { (completed) -> Void in
searchController.searchBar.becomeFirstResponder()
}
}
The problem is you are trying to access UI element(searchbarcontroller) before UI is completely loaded.
This can be done in 2 ways
Use main queue to show keypad
private func setupSearchController() {
self.navigationItem.searchController = searchController
searchController.definesPresentationContext = true
searchController.delegate = self
searchController.isActive = true
searchController.searchBar.delegate = self
DispatchQueue.main.async {
self.searchController.searchBar.becomeFirstResponder()
}
}
With this approach keypad will be only show at one time in viewDidLoad
Show keypad in viewDidAppear
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
DispatchQueue.main.async {
self.searchController.searchBar.becomeFirstResponder()
}
}
With this approach keypad will be always shown whenever screen appears.

How can I prevent UISearchController dismiss when cancel button pressed?

I want to just hide keyboard when user first press cancel button.
Just likes AppStore.app
I use UISearchController like that:
navigationItem.searchController = searchController
============== Update ==============
This Cancel button is hosted by UISearchController.
If you did search bar programmatically, you can add extension on your ViewController or else just use function call as below.
extension ViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
if let text = searchBar.text {
self.filterContent(text: text)
searchBar.resignFirstResponder()
}
}
}

disable hiding searchBar when scrolling

I am coding to setup search bar (not from storyboard)
here are my codes that related to searchbar:
var searchController = UISearchController(searchResultsController: nil)
func setupNavBar() {
self.navigationItem.title = "Tools"
self.navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.hidesSearchBarWhenScrolling = false
}
func configureSearchController() {
filteredData = toolsList.allTools
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.searchBarStyle = .minimal
searchController.searchBar.tintColor = .purple
tableView.tableHeaderView = searchController.searchBar
searchController.searchBar.placeholder = "Search for tools"
}
override func viewDidLoad() {
super.viewDidLoad()
setupNavBar()
tableViewConfigurations()
configureSearchController()
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
isSearching = true
tableView.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
isSearching = false
tableView.reloadData()
}
although with this line of code i ask to disable hiding search bar when scrolling, it is still hiding.
navigationItem.hidesSearchBarWhenScrolling = false
May i ask you to guide me to how i can disable it?
Thank you very much
Looking at Apple's docs I found this:
You must configure the searchController property for this property
[hidesSearchBarWhenScrolling] to have any effect. The navigation
controller hides and shows only the search bar provided by the search
controller in that property.
I'd try adding searchController to navigationItem.
#very_supercharged thanks 😊 i have transferred searchBar from table view to navigationBar
i have changed:
tableView.tableHeaderView = searchController.searchBar
to
navigationItem.searchController = searchController
And now, searchBar does not hide when scrolling.