Dismiss and swipe to dismiss issues with search controller active

Viewed 130

I am using a UISearchController search bar as the title view of my navigation bar in a modal view controller. I have it set up like this:

var searchController: UISearchController!

override func viewDidLoad() {
    super.viewDidLoad()
    searchController = UISearchController(searchResultsController: nil)
    searchController.searchResultsUpdater = self
    searchController.obscuresBackgroundDuringPresentation = false
    searchController.hidesNavigationBarDuringPresentation = false
    searchController.searchBar.showsCancelButton = false
    navigationItem.titleView = searchController.searchBar
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    // for whatever reason, it's necessary to make the search controller first responder
    // on the main queue. reference: https://stackoverflow.com/a/41657181/2335677
    DispatchQueue.main.async {
        self.searchController.searchBar.becomeFirstResponder()
    }
}

Everything is working great, except dismiss() and swipe-to-dismiss the modal aren't working when searchController.isActive = true

I can get around the dismiss() issue by setting it to inactive first:

@IBAction private func done(_ sender: UIBarButtonItem) {
    searchController.isActive = false
    dismiss(animated: true)
}

But I can't swipe down to dismiss the view controller as I mentioned. And I can't think of a workaround. I tried:

  1. Setting isModalInPresentation = false (not an option because my app target is iOS12)
  2. Playing with UIAdaptivePresentationControllerDelegate methods and trying to set searchController.isActive = false in some of those (didn't work)
  3. Setting definesPresentationContext = true (doesn't make a difference)

Does anyone have any other ideas?

1 Answers

If you want a separate screen just for searching and you just need a search bar in your navigation bar title like I did, it's easier to use a UISearchBar instead:

var searchBar: UISearchBar!

override func viewDidLoad() {
    super.viewDidLoad()
    searchBar = UISearchBar()
    searchBar.showsCancelButton = false
    navigationItem.titleView = searchBar
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    searchBar.becomeFirstResponder()
}

It looks the same and you get all the default behavior now since UISearchController isn't hijacking your view controller.

Related