In iOS 13 the behavior has changed so that by default when Navigation controller appears the search bar is visible (when UISearchController
is assigned to a navigationItem.searchController
). Some system apps appear with the search bar hidden (you need to swipe down for it to appear), but I don't see any specific property that would allow this. How to achieve this - maybe there is some property or some method to do that?

- 9,672
- 5
- 36
- 57
-
Navigation controllers don't have search bars by default so please update your question with details about what you are doing to get a search bar in place. – rmaddy Aug 20 '19 at 21:10
-
@rmaddy I will but just wandering if you really have no idea what I am doing as showing search bar in navigation controller is a standard procedure since iOS 11. – Ivan Ičin Aug 20 '19 at 21:39
-
There are different solutions so it is important for you to be clear on what exactly it is that you are doing. Your edit is far from enough detail. – rmaddy Aug 20 '19 at 22:24
-
@rmaddy as some people (possibly you) downvote, please answer what you are missing. Did you try to reproduce the problem with the description above. I can, and I don't see how implementation of searchbar controller would influence this as even the simplest one works. – Ivan Ičin Aug 21 '19 at 09:59
-
9This question seems clear to me. Navigation Items with search controllers assigned (thus with a search bar) behave differently in iOS 13 - they are visible on load. The obvious ideas (setting a content offset of the table, or programatically scrolling the table to a the first row) don't work. – Andrew Bennet Sep 04 '19 at 22:17
8 Answers
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
}

- 757
- 2
- 10
- 23
-
6This sounded promising and I've upvoted, but at least for me it doesn't have any effect, so possibly it works only in some cases. – Ivan Ičin Oct 07 '19 at 11:32
-
-
The original post is the exact problem I was having and this fixes it for me. Thank you @bunnyhero – sirshannon Oct 16 '19 at 20:23
-
Didn't fix it for me - is this the initial VC of your app btw or some other VC? – royherma Nov 02 '19 at 14:47
-
-
1I've got a Tab bar Controller (initial vc) -> root vc is Nav Controller with a UIViewController that has a UITableView and I'm not able to hide the search bar during load..tried everything :( @bunnyhero – royherma Nov 03 '19 at 12:29
-
2If it doesn't work for you in `viewWillLayoutSubviews` or `viewDidLayoutSubviews`, try doing it in `viewDidAppear` instead. That worked for me! – Avery Vine Dec 16 '19 at 23:20
To start with a hidden searchBar
, simply set the navigationItem.searchController
property after your table view (or collection view) has been populated with data.

- 8,259
- 1
- 54
- 67
-
None of these answers work for me. With this approach it either is not there at all until I switch to a different view and then back or it is already there. It seams a bit random and one time it just popped in, not smooth at all. I get the feeling they don't want to hide it. In this tutorial I'm following he said you 'might' have to pull down to see it, but when I run his example, its already there. https://www.raywenderlich.com/4363809-uisearchcontroller-tutorial-getting-started Must be dependant on the iOS version – Kurt L. Aug 13 '20 at 04:24
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.

- 1,776
- 1
- 17
- 28
-
I couldn't get the desired behavior even when I sequenced the searchBar setup after the collectionView reload. I finally got it working by delaying the searchBar setup using DispatchQueue.main.asyncAfter(deadline: .now() + 0.1). – theogood Mar 18 '22 at 13:47
This is what works for me. I have a UISegmentedControl that reloads the tableView when filter changes.
With FRC:
guard let count = try? fetchedResultsController.managedObjectContext.count(for: request) else { return }
called after tableView.reloadData()
navigationItem.searchController = count > 20 ? searchController : nil

- 21
- 1
I find this works:
self.searchController.searchBar.hidden = YES;
You will need to unhide at the appropriate time.

- 1,681
- 15
- 28
-
1I guess in some way it would work. But I don’t thin it is like in Mail app where the bar appears animated on scroll down – Ivan Ičin Sep 15 '19 at 16:41
I managed to make this work by setting isTransculent
false
on the navigationBar
and having initial data on UITableView
or UICollectionView
. If you have 0 cells initially and trigger reloadData
after some time (maybe a network call), SearchBar is visible initially. So have a dummy cell or something similar initially and load the data later, if that's the case for you.
navigationController?.navigationBar.isTranslucent = false

- 125
- 2
- 11
One should set searchController
after tableView
gets frame
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
super.scrollViewDidScroll(scrollView)
if !scrollView.frame.isEmpty, navigationItem.searchController == nil {
navigationItem.searchController = searchController
}
}

- 9,874
- 3
- 56
- 77
Swift 5.2 & iOS 13.3.1:-
Try like this. It works fine
navigationItem.hidesSearchBarWhenScrolling = false

- 97
- 3
-
1Have you tried? According to documentation it doesn’t work like that: https://developer.apple.com/documentation/uikit/uinavigationitem/2897296-hidessearchbarwhenscrolling – Ivan Ičin Feb 27 '20 at 09:25