iOS 11 SearchBar in NavigationBar

36,289

Solution 1

There's a new searchController property on navigationItem in iOS 11.

https://developer.apple.com/documentation/uikit/uinavigationitem/2897305-searchcontroller

Use like this...

if #available(iOS 11.0, *) {
     navigationItem.searchController = searchController
} else {
     // Fallback on earlier versions
     navigationItem.titleView = searchController?.searchBar
}

In Objective-C the if statement looks like this:

if (@available(iOS 11.0, *)) {

On iOS 11, if you don't set navigationItem.hidesSearchBarWhenScrolling = false, the search bar may initially be hidden, unless the user scrolls down to reveal it. If you do set it to false, it appears stacked below where the title would go without the user having to scroll.

Solution 2

You can change the height of UISearchBar in iOS 11 by adding a constraint of height 44:

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

Solution 3

I was having the same issue and after a few day googling the issue, I found this page - https://translate.google.com/translate?hl=en&sl=zh-CN&u=http://www.jianshu.com/p/262f6e34a7d3&prev=search.

This page leads to this git repo - https://github.com/DreamTravelingLight/searchBarDemo - this demo project shows how to use the old way with titleView to still have a searchBar without the sizing issue.

The key lines are these

_searchBar = [self addSearchBarWithFrame:CGRectMake(0, 0, kScreenWidth - 2 * 44 - 2 * 15, 44)];
UIView *wrapView = [[UIView alloc] initWithFrame:_searchBar.frame];
[wrapView addSubview:_searchBar];
self.navigationItem.titleView = wrapView;

If you embed the UISearchBar inside a view, and set that wrapView as the titleView, the UISearchBar will have the size you set for it, and will fit the nav bar as intended.

Thanks, David

Solution 4

If you really want to use the native UISearchBar (and avoid the needs of creating your custom components) in the iOS 11+ navigationBar, you could create a container view for that searchBar to have full control over the frame. This container view would be the superview of the searchBar you pass in.

Something like:

class SearchBarContainerView: UIView {

    let searchBar: UISearchBar

    required init?(coder aDecoder: NSCoder) {
        searchBar = UISearchBar()
        super.init(coder: aDecoder)
    }

    init(searchBar: UISearchBar) {
        self.searchBar = searchBar
        super.init(frame: CGRect(x: 0.0, y: 0.0, width: 0.0, height: 44.0))
        addSubview(searchBar)
    }

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

And then:

let containerView = SearchBarContainerView(searchBar: searchController.searchBar)
containerView.frame.size.width = navigationController?.navigationBar.frame.size.width ?? 0.0
navigationItem.titleView = containerView

Note that this is just a quick demo and is not ready for navigationBar frame changes (display rotation etc.). You could solve that with e.g. autoresizingMask.

Solution 5

Make a summary in iOS 14+

First to fix push cause extra height:

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

Second to fix pop to origin height:

extendedLayoutIncludesOpaqueBars = true

All above code set in the controller with search bar.

Share:
36,289
PatrickDotStar
Author by

PatrickDotStar

Updated on July 05, 2022

Comments

  • PatrickDotStar
    PatrickDotStar almost 2 years

    With iOS 11 Apple has redesigned the UISearchBar by making the corners rounder and the height bigger. Adding a UISearchBar to the navigationBar is pretty simple by just setting it as the titleView of the navigationItem using navigationItem.titleView = searchBar.

    However, in iOS 11 it does not seem to work anymore as expected. Have a look at the screens where we compare the same setup using iOS 10 and iOS 11

    iOS 10 enter image description here

    iOS 11 enter image description here

    You can clearly see that the SearchBar increases the size of the NavigationBar but the bar buttons do not get aligned correctly. Also the searchBar does not use the available space on the left anymore.

    Putting the searchBar into a wrapper view to get the cancel button on iPad as described here Cancel button is not shown in UISearchBar also does not seem work anymore since the searchBar is then not visible at all.

    If anyone has similar issues or already knowns how to fix/improve this I would be very thankful.

    This was built using Xcode 9 Beta 4. Maybe future releases will fix this issue.

    UPDATE:

    Since this does not get fixed we decided to use following solution. We added a new UIBarButtonItem to the NavBar which then presents a new ViewController where we only put a searchBar and nothing else into the NavBar which seems to work. Using the selected answer may be the best solution since Apple with iOS 11 wants us to use this new design even if it does not give us the result we originally wanted. Another way to possible solve this could be a custom SearchBar but this is another topic.

  • Justin Domnitz
    Justin Domnitz almost 7 years
    My answer is similar to @cook answer, but I thought the link and the code might help clarify a bit.
  • Molanda
    Molanda almost 7 years
    This will not give the results as original described. Using the searchController property will put the search bar below the navigation.
  • coolcool1994
    coolcool1994 over 6 years
    This makes top and bottom bezel shorter. I tried this objective-c solution: [[self.notesSearchBar.heightAnchor constraintEqualToConstant:44.0] setActive:YES], but I dont like this solution because it makes top bottom margin thinner and weird.
  • Christian Ascone
    Christian Ascone over 6 years
    This worked for me. It repositions my search bar maintaining the correct layout.
  • Starchand
    Starchand over 6 years
    This works on iPhone but doesn't work on iPad for me.
  • Rushabh
    Rushabh over 6 years
    This is the correct solution however, especially if you are targeting both iOS 10 and iOS 11 with your app
  • Delorean
    Delorean over 6 years
    This solves the height issue, but does not address the width problem as posted by the author.
  • Kepa Santos
    Kepa Santos over 6 years
    Why kScreenWidth - 2 * 44 - 2 * 15?
  • tech savvy
    tech savvy over 5 years
    Do you know the navigationbar height in this case? Will it change?
  • ethanhuang13
    ethanhuang13 over 4 years
    This works! Also update containerView.frame in override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { coordinator.animate(alongsideTransition: { // here }... } is enough.