Search code examples
iosswiftuinavigationcontrolleruisearchcontrolleruinavigationitem

How do I display a UISearchController on a UINavigationItem without an underlying UIScrollView?


Maybe this is impossible, but I always assumed you could just throw a UISearchController instance onto any old view controller's navigationItem and get a search bar. It seems to me like no matter what I try, I can't get it to work. It's making me think this behavior is hardcoded to only work when the view controller's view property is a subclass of UIScrollView.

I hope this is just a red herring. If I missed something obvious, please help! This is infuriating.

Here's what I did:

import UIKit.UIViewController

class MainViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationItem.hidesSearchBarWhenScrolling = false

        navigationItem.searchController = {
            let searchController = UISearchController()
            searchController.hidesNavigationBarDuringPresentation = false
            searchController.dimsBackgroundDuringPresentation = false
            searchController.obscuresBackgroundDuringPresentation = false
            return searchController
        }()
    }
}

No search bar ever appears on screen. It just looks like a regular old navigation bar.


Solution

  • The UISearchController initializer should be let searchController = UISearchController(searchResultsController: nil) or replace nil with a seperate controller to display the search results.

    If your viewController is in a UINavigationController stack then the above code should work (with the corrected initializer). Otherwise you will need to create a UINavigationBar and add it to the view. Then add the searchController.searchBar to the navigationItem.titleView

        let navigationBar = UINavigationBar()
        view.addSubview(navigationBar)
        navigationBar.barTintColor = UIColor.gray
        navigationBar.translatesAutoresizingMaskIntoConstraints = false
        navigationBar.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        navigationBar.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        navigationBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        navigationBar.delegate = self
    
        navigationBar.items = [navigationItem]
    
        navigationItem.searchController = {
            let searchController = UISearchController(searchResultsController: nil)
            searchController.hidesNavigationBarDuringPresentation = false
            searchController.dimsBackgroundDuringPresentation = false
            searchController.obscuresBackgroundDuringPresentation = false
            return searchController
        }()
    
        navigationItem.titleView = navigationItem.searchController?.searchBar