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 sett
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.
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.
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
.
This helped me:
if ([self.navigationItem respondsToSelector:@selector(setSearchController:)])
{
[self.navigationItem performSelector:@selector(setSearchController:) withObject:self.searchController];
}
else
{
self.tableView.tableHeaderView = self.searchController.searchBar;
}
I tried out with searchController
andsearchBar
but found thatsearchBar
is meeting my requirements(search on click of the search button).
-(void)searchBarSetUp{
//Search button to reload the radio content.
self.searchButton.action = @selector(addSearchBarToNavigationTitleView);
self.searchButton.target = self;
//search bar initialization
searchBar = [[UISearchBar alloc] initWithFrame:CGRectZero];
searchBar.delegate = self;
searchBar.showsCancelButton = YES;
[searchBar sizeToFit]; }
-(void)addSearchBarToNavigationTitleView {
// Install the search bar as the table header.
self.navigationItem.titleView = searchBar;}
I too faced difficulties to handle the black screen if I am using searchControl
.
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
}