iOS 11 SearchBar in NavigationBar
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.
![PatrickDotStar](https://i.stack.imgur.com/8WfvC.png?s=256&g=1)
PatrickDotStar
Updated on July 05, 2022Comments
-
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
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 almost 7 yearsMy answer is similar to @cook answer, but I thought the link and the code might help clarify a bit.
-
Molanda almost 7 yearsThis will not give the results as original described. Using the searchController property will put the search bar below the navigation.
-
coolcool1994 over 6 yearsThis 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 over 6 yearsThis worked for me. It repositions my search bar maintaining the correct layout.
-
Starchand over 6 yearsThis works on iPhone but doesn't work on iPad for me.
-
Rushabh over 6 yearsThis is the correct solution however, especially if you are targeting both iOS 10 and iOS 11 with your app
-
Delorean over 6 yearsThis solves the height issue, but does not address the width problem as posted by the author.
-
Kepa Santos over 6 yearsWhy kScreenWidth - 2 * 44 - 2 * 15?
-
tech savvy over 5 yearsDo you know the navigationbar height in this case? Will it change?
-
ethanhuang13 over 4 yearsThis works! Also update containerView.frame in
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { coordinator.animate(alongsideTransition: { // here }... }
is enough.