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

8

17

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?

Semang answered 20/8, 2019 at 21:8 Comment(5)
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.Hanger
@Hanger 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.Mandibular
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.Hanger
@Hanger 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.Mandibular
This 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.Liederkranz
A
9

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
}

Askwith answered 6/10, 2019 at 23:33 Comment(7)
This 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.Mandibular
@IvanIčin darn :(Askwith
The original post is the exact problem I was having and this fixes it for me. Thank you @AskwithGrimmett
Didn't fix it for me - is this the initial VC of your app btw or some other VC?Sinistrad
@Sinistrad This isn't the initial VC of my app.Askwith
I'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 :( @AskwithSinistrad
If it doesn't work for you in viewWillLayoutSubviews or viewDidLayoutSubviews, try doing it in viewDidAppear instead. That worked for me!Neese
M
6

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

Mouthwash answered 11/8, 2020 at 11:43 Comment(1)
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. raywenderlich.com/… Must be dependant on the iOS versionStella
H
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.

Haemal answered 26/10, 2021 at 10:14 Comment(1)
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).Fabyola
G
1

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
Gobioid answered 30/7, 2021 at 0:26 Comment(0)
R
0

I find this works:

self.searchController.searchBar.hidden = YES;

You will need to unhide at the appropriate time.

Reign answered 14/9, 2019 at 8:0 Comment(1)
I 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 downMandibular
V
0

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
Visakhapatnam answered 15/4, 2020 at 15:7 Comment(0)
Q
0

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
    }
}
Quadrivial answered 20/2, 2021 at 9:48 Comment(0)
K
-2

Swift 5.2 & iOS 13.3.1:-

Try like this. It works fine

        navigationItem.hidesSearchBarWhenScrolling = false
Kossuth answered 27/2, 2020 at 7:55 Comment(1)
Have you tried? According to documentation it doesn’t work like that: developer.apple.com/documentation/uikit/uinavigationitem/…Mandibular

© 2022 - 2024 — McMap. All rights reserved.