I have a view controller in which I dynamically create a UISearchController and assign it to self.navigationItem.searchController.
class MyViewController: UIViewController, UISearchBarDelegate {
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.searchController = searchController
searchController.searchBar.delegate = self
// launch the app directly into this search text box
searchController.searchBar.becomeFirstResponder()
}
func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool {
// I tried this
searchBar.resignFirstResponder()
// and this
searchBar.endEditing(true)
// and finally this
return true
}
}
The keyboard hides away when the user touches anywhere outside the searchbar and the screen goes back to its brightness. That is the expected behavior.
However, when the user taps the [Search] button within the on-screen-keyboard, the keyboard goes away, but the screen is kept dim. None of the sub-views are useable, except if the user taps the search bar again, then the keyboard comes back.
So in short, the only way for the user to continue using the view controller, is not to hit the [search] button, which is counter-intuitive.
am I missing something?
In viewDidLoad(), add the following line:
searchController.obscuresBackgroundDuringPresentation = false
From the documentation: If you use the same view controller to display the searchable content and search results, it is recommended that you set this property to false. The default value of this property is true.
I implemented a search bar inside a navigation controller, it's working fine but the cancel button tap delegate method is not being called. Please help:
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
//This function is not being called
}
let searchBarCnt = UISearchController(searchResultsController: nil)
navigationItem.searchController = searchBarCnt
navigationItem.hidesSearchBarWhenScrolling = true
self.navigationController?.view.backgroundColor = UIColor.white
searchBarCnt.delegate = self
searchBarCnt.searchBar.delegate = self
The function delegate is not being called because you are missing the definesPresentationContext:
Determines which parent view controller's view should be presented over for presentations of type
UIModalPresentationCurrentContext. If no ancestor view controller has this flag set, then the presenter
will be the root view controller.
you may enable such flag in this way:
import UIKit
class ViewController: UIViewController, UISearchBarDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.searchController = UISearchController(searchResultsController: nil)
self.navigationItem.searchController?.searchBar.delegate = self
self.definesPresentationContext = true
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
print("searchBarCancelButtonClicked")
}
}
Note:
without definesPresentationContext, you are not really touching the cancel button (when you try to touch it), you are just dismissing the context (you may notice a "silent" glitch in the background focus), suchlike
a popover is being dismissed.
When you click the Cancel button which appears next to search bar delegate method won't be called.
Try to click on search button on keyboard and check whether cancel button delegate method is getting called or not
I am trying to use UISearchController to display a search bar along with scope bar in iOS 11.
Here is the code that I am using to setup the search controller
let searchController = UISearchController(searchResultsController: nil)
searchController.delegate = self
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.showsScopeBar = true
searchController.searchBar.scopeButtonTitles = ["1", "2", "3", "4"]
searchController.searchBar.delegate = self
definesPresentationContext = true
I want a search bar with a scope bar that is always visible.
The above code works fine when the view controller loads and it displays the search bar along with the scope bar.
But, once the search controller becomes active and is then dismissed, iOS hides the scope bar on dismiss of the search controller and it only displays the search bar.
I tried to solve this issue by adding the following code in didDismissSearchController, but the scope bar and the search bar comes on top of each other instead of the scope bar coming below the search bar (like the image below). Adding this code to searchBarTextDidBeginEditing(_ searchBar: UISearchBar) or searchBarTextDidEndEditing(_ searchBar: UISearchBar) has no effect.
searchController.searchBar.showsScopeBar = true
searchController.searchBar.sizeToFit()
Try adding this this to your search controller setup:
searchController.sizeToFit()
Then add this:
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
self.searchBar.sizeToFit()
return true
}
func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool {
self.searchBar.sizeToFit()
return true
}
Don't put searchController.searchBar.showsScopeBar = true in the search bar functions. That creates a problem for some reason.
I'm trying out UISearchController for iOS 8 right now. When I click the cell, it will push the segue and show another view controller. However, the search controller/bar is still there on the next controller. Also, I notice that the status bar background is white, while it should be grey as the searchBar background color is grey. Is there anything that I miss?
This is the codes that I used to initialise the search controller
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.sizeToFit()
tableView.tableHeaderView = searchController.searchBar
}
Screenshot:
Manual stop UISearchController in prepareForSegue
searchController.active = false
Or add this in viewDidLoad
searchController.definesPresentationContext = true
I've added a UISearchController to my application and set it's searchBar to the titleView of my navigationItem.
This works but I am seeing the cancel button despite having set showsCancelButton to false.
searchController = UISearchController(searchResultsController: searchResultsController)
searchController.searchResultsUpdater = searchResultsUpdater
// Configure the searchBar
searchController.searchBar.placeholder = "Find Friends..."
searchController.searchBar.sizeToFit()
searchController.searchBar.showsCancelButton = false
self.definesPresentationContext = true
navigationItem.titleView = searchController.searchBar
I agree, it seems like a bug. The problem is that the searchController keeps resetting the showsCancelButton property of the searchBar. I found a solution that involves:
subclassing UISearchBar to ignore setShowsCancelButton.
to make the searchController use that subclass, you have to subclass UISearchController.
And then you find that the searchBar is not triggering the search controller's delegate methods, so you have to trigger them separately...
Convoluted, but it seems to do the trick. You can find the full answer here.
This appears to be a bug in iOS. The same behavior I've described can be seen in the example project supplied by Apple
https://developer.apple.com/library/ios/samplecode/TableSearch_UISearchController/Introduction/Intro.html
The documentation states that the default for this is NO but this doesn't seem to be the case. Setting showsCancelButton to NO seems to have no effect.
I have filed a radar for this and am waiting to hear back.
Easy solution in Swift3 - we need to make CustomSearchBar without cancel button and then override the corresponding property in new CustomSearchController:
class CustomSearchBar: UISearchBar {
override func setShowsCancelButton(_ showsCancelButton: Bool, animated: Bool) {
super.setShowsCancelButton(false, animated: false)
}}
class CustomSearchController: UISearchController {
lazy var _searchBar: CustomSearchBar = {
[unowned self] in
let customSearchBar = CustomSearchBar(frame: CGRect.zero)
return customSearchBar
}()
override var searchBar: UISearchBar {
get {
return _searchBar
}
}}
In MyViewController I initialize and configure searchController using this new custom subclass:
var mySearchController: UISearchController = ({
// Display search results in a separate view controller
// let storyBoard = UIStoryboard(name: "Main", bundle: Bundle.main)
// let alternateController = storyBoard.instantiateViewController(withIdentifier: "aTV") as! AlternateTableViewController
// let controller = UISearchController(searchResultsController: alternateController)
let controller = CustomSearchController(searchResultsController: nil)
controller.searchBar.placeholder = NSLocalizedString("Enter keyword (e.g. iceland)", comment: "")
controller.hidesNavigationBarDuringPresentation = false
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.searchBarStyle = .minimal
controller.searchBar.sizeToFit()
return controller
})()
I had to correct by putting in a little hack...
Setting the alpha to 0.0 on viewDidLoad because he screen will flash.
Before you ask...willPresentSearchController will not work.
extension GDSearchTableViewController: UISearchControllerDelegate {
func didPresentSearchController(searchController: UISearchController) {
searchController.searchBar.setShowsCancelButton(false, animated: false)
searchController.searchBar.becomeFirstResponder()
UIView.animateWithDuration(0.1) { () -> Void in
self.view.alpha = 1.0
searchController.searchBar.alpha = 1.0
}
}
}
We wanted the search bar to have no Cancel button initially, but have it appear when the user tapped in the search bar.
Then we wanted the Cancel button to disappear if user tapped Cancel, or otherwise the search bar lost first responder.
What finally worked for me:
On create:
searchBar.showsCancelButton = NO;
We use a subclass of UISearchBar and override searchBarShouldBeginEditing thusly:
-(BOOL)searchBarShouldBeginEditing:(UISearchBar*)searchBar {
self.showsCancelButton = YES;
return YES;
}
We also override resignFirstReponder (in the UISearchBar subclass) thusly:
-(BOOL)resignFirstResponder
{
self.showsCancelButton = NO;
return [super resignFirstResponder];
}
I would also add
searchController.hidesNavigationBarDuringPresentation = false
searchController.delegate = self
searchController.searchBar.delegate = self
See if assigning those delegates will help.
I try to help you man but I'm not sure that I find the real problem.
According to Apple Documentation:
showsCancelButton
boolean property that indicating whether the cancel button is
displayed
But for hide the cancel button maybe you should use:
setShowsCancelButton(_:animated:)
I hope that can be helpful.
You can subclass UISearchBar and override method layoutSubviews
super.layoutSubviews()
self.showsCancelButton = false
my solution was to set the attribute every time anew when I used the searchcontroller respectively its searchbar. I initialized the searchcontroller lazily without setting the attribute and then did
searchController.searchBar.showsCancelButton = false
every time before search began.
You could do this in the UISearchControllerDelegate methods i.e...
This worked for me (iOS 10):
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.searchController.searchBar.showsCancelButton = NO;
}
It may be helpful to note that this has changed on iOS 13 and quote Apple's documentation on showsCancelButton, currently only available on UISearchBar.h and not on developer.apple.com
/* New behavior on iOS 13.
If the search bar is owned by a UISearchController, then using the setter
for this property (as well as -setShowsCancelButton:animated:) will implicitly
set the UISearchController's automaticallyShowsCancelButton property to NO.
*/
automaticallyShowsCancelButton has been introduced on iOS 13.0 and should clarify what #pbasdf had already pointed out in his answer: that the buggy behavior is something intrinsic to UISearchController.
What about setting it with [searchBar setShowsCancelButton:NO animated:NO];
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UISearchBar_Class/#//apple_ref/occ/instm/UISearchBar/setShowsCancelButton:animated: