How to initally hide searchbar in Navigation controller on iOS 13?

Solution 1:

Via experimentation, I have discovered that if you delay assigning the search controller to the navigation item until viewWillLayoutSubviews or viewDidLayoutSubviews, the search controller starts out hidden, as desired. However, this if you do this on iOS 12 or earlier, the search controller will not be revealed when scrolling down.

I ended up doing the following with a messy version check, which is working for me:

override func viewDidLoad() {
    super.viewDidLoad()

    searchController = /* make search controller... */

    if #available(iOS 13, *) {
        // Attaching the search controller at this time on iOS 13 results in the
        // search bar being initially visible, so assign it later
    }
    else {
        navigationItem.searchController = searchController
    }
}

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    navigationItem.searchController = searchController
}

Solution 2:

To start with a hidden searchBar, simply set the navigationItem.searchController property after your table view (or collection view) has been populated with data.

Solution 3:

Inspired by bunnyhero's answer I put the code responsible for setting the UISearchController in navigationItem inside the viewDidAppear method. Seems to be working every time for me on iOS 14/15

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    if navigationItem.searchController == nil {
        navigationItem.searchController = searchController
    }
}

Edit: I was overly optimistic. On iOS 15.2 this method stopped working for me. What I did to fix it was to move the code after reloading my table/collection view.