UISearchController searchBar showsCancelButton not being respected

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 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:

  1. subclassing UISearchBar to ignore setShowsCancelButton.
  2. to make the searchController use that subclass, you have to subclass UISearchController.
  3. 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.


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
        }
    }
}

Tags:

Ios

Xcode

Swift