UISearchBar increases navigation bar height in iOS 11

38,552

Solution 1

I got black line under NavigationBar with SearchBar in iOS 11 in two cases:

  • when i pushed another ViewControllers from ViewController with UISearchBar enter image description here

  • when i dismissed ViewController with UISearchBar with "drag right to dismiss" enter image description here

My solution was: adding this code to my ViewController with UISearchBar:

-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    [self.navigationController.view setNeedsLayout]; // force update layout
    [self.navigationController.view layoutIfNeeded]; // to fix height of the navigation bar
}

Swift 4 Update

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    navigationController?.view.setNeedsLayout() // force update layout
    navigationController?.view.layoutIfNeeded() // to fix height of the navigation bar
}

Solution 2

You can add a constraint of height 44 to the search bar for iOS 11.

// Swift

if #available(iOS 11.0, *) {
    searchBar.heightAnchor.constraint(equalToConstant: 44).isActive = true
}

// Objective-C

if (@available(iOS 11.0, *)) {
    [searchBar.heightAnchor constraintEqualToConstant:44].active = YES;
}

Solution 3

I believe in iOS 11 UISearchBar now has the height equals to 56, and UINavigationBar uses autolayout to fit its subviews hence it increases the height. If you still want to have UISearchBar as titleView as in pre-iOS 11, I found out the best way to do it is to embed UISearchBar in a custom view, and set this view's height to 44, and assign it to navigationItem.titleView

class SearchBarContainerView: UIView {  

    let searchBar: UISearchBar  

    init(customSearchBar: UISearchBar) {  
        searchBar = customSearchBar  
        super.init(frame: CGRect.zero)  

        addSubview(searchBar)  
    }

    override convenience init(frame: CGRect) {  
        self.init(customSearchBar: UISearchBar())  
        self.frame = frame  
    }  

    required init?(coder aDecoder: NSCoder) {  
        fatalError("init(coder:) has not been implemented")  
    }  

    override func layoutSubviews() {  
        super.layoutSubviews()  
        searchBar.frame = bounds  
    }  
}  

class MyViewController: UIViewController {  

    func setupNavigationBar() {  
        let searchBar = UISearchBar()  
        let searchBarContainer = SearchBarContainerView(customSearchBar: searchBar)  
        searchBarContainer.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 44)  
        navigationItem.titleView = searchBarContainer  
    }  
} 

Solution 4

try this code on "ACKNOWLEDGEMENTS" view controller in viewDidLoad

self.extendedLayoutIncludesOpaqueBars = true

Solution 5

Thank you all! I finally found a solution.

Adding the following code to ViewController with UISearchBar.

  1. First step: viewDidLoad
-(void)viewDidLoad
{
    [super viewDidLoad];
    self.extendedLayoutIncludesOpaqueBars = YES;
    ...
}
override func viewDidLoad() {
    super.viewDidLoad()
    self.extendedLayoutIncludesOpaqueBars = true
}
  1. Second step:viewWillDisappear
-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
     // force update layout
    [self.navigationController.view setNeedsLayout]; 
    // to fix height of the navigation bar
    [self.navigationController.view layoutIfNeeded];  
}
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        navigationController?.view.setNeedsLayout() // force update layout
        navigationController?.view.layoutIfNeeded() // to fix height of the navigation bar
    }
Share:
38,552
radioaktiv
Author by

radioaktiv

Updated on July 08, 2022

Comments

  • radioaktiv
    radioaktiv almost 2 years

    I have my UISearchBar being part of the navigation bar like:

     let searchBar = UISearchBar()
     //some more configuration to the search bar
     .....
     navigationItem.titleView = searchBar
    

    After updating to iOS 11 something weird happened to the search bar in my app. On iOS 10 and prior I had my navigation bar looking like:

    enter image description here

    Now with iOS 11 I have:

    enter image description here

    As you can see there is difference in the rounding of the two search bars which does not bothers me. The problem is that the search bar increases the height of the navigation bar. So when I go to another controller it looks weird too:

    enter image description here

    In fact that weird black line's height plus the current navigation bar's height is equal to the height of navigation bar shown in the second picture ...

    Any ideas how to get rid of the black line and having consistent navigation bar height across all view controllers ?

  • radioaktiv
    radioaktiv over 6 years
    Correct. This is how I managed to solved it actually. As well as calling searchBar.sizeToFit() in the viewWillAppear.If you add the call to sizeToFit() I will accept your answer :) .
  • zgjie
    zgjie over 6 years
    @radioaktiv I didn't write sizeToFit() and it works for me.
  • Iulian Onofrei
    Iulian Onofrei over 6 years
    But what exactly changed that caused this problem?
  • zgjie
    zgjie over 6 years
    @IulianOnofrei it use auto layout now, not before.
  • Iulian Onofrei
    Iulian Onofrei over 6 years
    I mean, in iOS 11, what did Apple change to UISearchBar.
  • zgjie
    zgjie over 6 years
    @IulianOnofrei made it’s height 56 in iOS 11
  • Iulian Onofrei
    Iulian Onofrei over 6 years
    Is the change documented somewhere? I couldn't find it here.
  • Chris Yim
    Chris Yim over 6 years
    This works, but searchBar still has a 56 height. <NSContentSizeLayoutConstraint: UISearchBar.height =56>,<NSLayoutConstraint UISearchBar.height of=44>
  • Oscar Apeland
    Oscar Apeland over 6 years
    FYI, you can modify the frame without making a variable for it; CGRect().insetBy(dx:dy:) and CGRect().offsetBy(dx:dy:), in this case - searchController.searchBar.frame = searchController.searchBar.frame.insetBy(dx: 0, dy: -12)
  • Michael Pirotte
    Michael Pirotte over 6 years
    I want to do the same thing as you, but I'll wait till a more elegant solution comes up. Thanks for sharing anyway.
  • Christopher Smit
    Christopher Smit over 6 years
    Although this works for bringing the height back to normal, if I tap on my searchbar, for some reason it cuts off the bottom part of the searchbar. Any ideas why this happens or anyone else having this issue?
  • Bill Noto
    Bill Noto over 6 years
    Here's the obj-c version: [searchBar.heightAnchor constraintEqualToConstant:44].active = YES; but one issue is that while this fixes the height issue, it reeks havoc on the rest of UISearchController's view. E.g., the bar buttons are hidden at first and the magnifying glass looks half drawn, or as if something is on top of it. Anyone else?
  • Gustavo_fringe
    Gustavo_fringe over 6 years
    This solution worked but when you click the search bar the height is reset.
  • OtakuFitness
    OtakuFitness over 6 years
    Totally weird looking if you use this code because it just narrows the navigation bar but the height of the search bar is still 56.
  • Malav Soni
    Malav Soni over 6 years
    This will create issue when you do this in landscape orientation.
  • Malav Soni
    Malav Soni over 6 years
    This work correctly but have issue when you change it to landscape from portrait.
  • Ryan H.
    Ryan H. over 6 years
    Great solution if you're not using auto layout. So far, this seems to work for landscape mode too, in the simulator.
  • Gustavo_fringe
    Gustavo_fringe over 6 years
    Did anyone else find a solution? doing this creates a lot of weird behavioral issues with the search bar.
  • Ross
    Ross over 6 years
    This is not enough answer. When you click on the field, the size is still messed up.
  • Jeff
    Jeff over 6 years
    Life saving answer! Size to fit not needed. If you have issues something else is wrong.
  • de.
    de. over 6 years
    I have posted a solution that fixes orientation change issues.
  • tanya
    tanya over 6 years
    I was able to get rid of the left nav button on top of the searchBar after loading by adding setNeedsUpdateConstraints/setNeedsLayout/layoutIfNeeded for navbar in viewDidLoad (searchBar is assigned to titleView in storyboard). The only way I found to fix layout constraints issues when rotating were in viewWillTransitionToSize:...set titleView to nil and in completion block of coordinator animateAlongsideTransition, re-set titleView to searchBar and update constraints/call setNeedsUpdateConstraints/setNeedsLayout/layoutIfNeeded for navbar.
  • Charlie Hung
    Charlie Hung over 6 years
    This answer solved all problems. zgjie's answer is great but search bar frame still changed after tap the textfield.
  • code4latte
    code4latte over 6 years
    This removed the black view in the new viewcontroller but when returning to this viewcontroller(the one that contains searchBar), the rootView actually moved up a little bit.
  • mmh02
    mmh02 over 6 years
    Thanks! This is the solution I ended up going with, since I'm not using translucent bars.
  • Amrit Sidhu
    Amrit Sidhu over 6 years
    Indeed this should be the answer. But I would like to add that place this piece of code in both the controller that over and below the search bar controller.
  • douglasd3
    douglasd3 about 6 years
    That worked for me, but a had to add navigationController?.view.layoutSubviews() in viewWillDisappear.
  • DrMickeyLauer
    DrMickeyLauer about 6 years
    This does not seem to make a UISearchController reappear which – in iOS11 – might be contained in the UINavigationItem. Do you have an idea how to do that?
  • Ethan Allen
    Ethan Allen about 6 years
    I'm pretty sure in iOS 11.4 this doesn't work anymore. Apple sets a hard height constraint on the search bar. If you break it by setting NSAutoresizingMaskLayoutConstraint = false, Apple just enforces a _UITemporaryLayoutHeight to override you.
  • Anirudha Mahale
    Anirudha Mahale over 5 years
    This works very well, I would really appreciate if you just tell us what extendedLayoutIncludesOpaqueBars property does.
  • Admin
    Admin over 5 years
    extendedLayoutIncludesOpaqueBars expand your view (self.view) under the navigation and status bar. If you add a subview to the view(For example, UIImageView) and set it constraint to the top-left of the view and run the application, you will see the different when you set this property between true and false.
  • Reconquistador
    Reconquistador over 5 years
    You are missing calling of super.viewDidAppear(animated)
  • Parthpatel1105
    Parthpatel1105 over 5 years
    I have been finding solution since long time and finally I get the perfect solution.
  • Shivam Pokhriyal
    Shivam Pokhriyal almost 5 years
    @Gustavo_fringe Did you find any solution for this.
  • Abd Al-rhman Taher Badary
    Abd Al-rhman Taher Badary almost 5 years
    Use this with caution as for me it made the whole app freeze when is tried to swipe back to pervious view controller
  • V V
    V V over 4 years
    This doesnt work in iOS 13. Any workaround for this?
  • Sagar Daundkar
    Sagar Daundkar about 4 years
    This solution really give a big relief to me thanks @andrew