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?
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
}
viewWillLayoutSubviews
or viewDidLayoutSubviews
, try doing it in viewDidAppear
instead. That worked for me! –
Neese To start with a hidden searchBar
, simply set the navigationItem.searchController
property after your table view (or collection view) has been populated with data.
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.
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
I find this works:
self.searchController.searchBar.hidden = YES;
You will need to unhide at the appropriate time.
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
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
}
}
Swift 5.2 & iOS 13.3.1:-
Try like this. It works fine
navigationItem.hidesSearchBarWhenScrolling = false
© 2022 - 2024 — McMap. All rights reserved.