How can I show a UISearchBar in the NavigationBar?
I can't figure out how to do this.
Your help is very much appreciated.
To put searchBar into the center of navigationBar:
self.navigationItem.titleView = self.searchBarTop;
To put searchBar to the left/right side of navigationBar:
UIBarButtonItem *searchBarItem = [[UIBarButtonItem alloc] initWithCustomView:searchBar];
self.navigationItem.rightBarButtonItem = searchBarItem;
As of iOS 7, the UISearchDisplayController supports this by default. Set the UISearchDisplayController's displaysSearchBarInNavigationBar = YES to get this working easily.
Per the documentation:
Starting in iOS 7.0, you can use a search display controller with a navigation bar (an instance of the UINavigationBar class) by configuring the search display controller’s displaysSearchBarInNavigationBar and navigationItem properties.
As one commenter noted, using searchDisplayController.displaysSearchBarInNavigationBar = true ends up hiding any existing left/right bar button items.
I've found two different ways of adding a searchBar to a navigationBar using iOS7's new property on searchDisplayController.
1) Nib Based Approach
If you're using a .xib, you can set a User Defined Runtime Attribute for this value and for whatever reason, the leftBarButtonItem stays in tact. I have not tested it with a rightBarButtonItem.
2) Code (Timing Matters)
If you want to implement in code, timing seems to matter. It seems that you must add the searchBar to the navigationBar first, then set your barButtonItem.
- (void)viewDidLoad
{
...
self.searchDisplayController.displaysSearchBarInNavigationBar = true;
self.navigationItem.leftBarButtonItem = [UIBarButtonItem new];
...
}
Check out Apple's UICatalog sample code. It shows how to use the new UISearchController in three different ways: modally, in nav bar, and below the navigation bar.
Objective C code snippet for UISearchBar in NavigationBar
- (void)viewDidLoad {
UISearchController *searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
if (#available(iOS 11.0, *)) {
self.navigationItem.searchController = searchController;
} else {
self.navigationItem.titleView = searchController.searchBar;
}
}
Read more here
Related
I am trying to add a UISearchBar to my UINavigationItem but the scope bar is showing behind the search bar. Any ideas to fix that problem?
iOS: 11.2
xCode: 9.2
my code:
- (void)viewDidLoad
{
[super viewDidLoad];
self.mySearchBar = [[UISearchBar alloc] init];
self.mySearchBar.delegate = self;
self.mySearchBar.scopeButtonTitles = #[#"item 1", #"item 2", #"item 3"];
self.navigationItem.titleView = self.mySearchBar;
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
[self.mySearchBar setShowsScopeBar: TRUE];
[self.mySearchBar setShowsCancelButton:TRUE animated:TRUE];
return TRUE;
}
the result:
Context
The problem is that UINavigationBar provides a very specific and familiar iOS style that Apple wants to keep the same across apps. Default navigation bars don't expand to fit their contents.
When you set set the titleView of navigation item, you are expected to lay out the contents in that view based on the size of the navigation bar, not the other way around.
Solutions
There are several possible solutions:
Change the behavior of that instance of UINavigationBar (not recommended).
Place the UISearchBar underneath the navigation bar as a regular subview.
Use UISearchController
The first option should definitely not be your first solution because it requires you to solve many thorny issues. Use as a last resort.
Option 2 requires the following code changes. Replace self.navigationItem.titleView = self.mySearchBar with:
[self.view addSubview:self.mySearchBar];
UILayoutGuide *guide = self.view.safeAreaLayoutGuide;
[self.mySearchBar.topAnchor constraintEqualToAnchor:guide.topAnchor].active = YES;
[self.mySearchBar.rightAnchor constraintEqualToAnchor:guide.rightAnchor].active = YES;
[self.mySearchBar.leftAnchor constraintEqualToAnchor:guide.leftAnchor].active = YES;
And you are also missing code to resize the UISearchBar after showing the scope bar. The view does not resize itself. So, in your searchBarShouldBeginEditing: method, add this line just before return: [self.mySearchBar sizeToFit];
The third solution may be easier for you depending on your use case. That is, use UISearchController, which includes it's own UISearchBar anchored at the top of the screen. It would look just like solution #2 above as shown in the image below:
Here is a great tutorial on using UISearchController if you are interested.
Referred here and here. No answer in first link. In the second link, though the answer is not accepted, but the link to apple developer forum gives error.
Before iOS 11 :
iOS 11 :
Note : Same device same code.
Also, this would mean, all apps using this feature have to be republished ?
Adding these lines fixed it for me:
override func viewDidLayoutSubviews() {
self.searchController.searchBar.sizeToFit()
}
I can get the initial appearance to display correctly in iOS11 using the following code (as per greg's answer):
[self.searchController.searchBar sizeToFit];
if (#available(iOS 11.0, *)) {
self.navigationItem.searchController = self.searchController;
self.navigationItem.hidesSearchBarWhenScrolling = NO;
} else {
// Fallback on earlier versions
self.tableView.tableHeaderView = self.searchController.searchBar;
}
However, if the app is backgrounded then restored while the search bar was active, the appearance would end up overlapped as shown in Nitish's second screenshot above.
I was able to fix that with the following workaround:
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
self.searchController.searchBar.showsScopeBar = NO;
[self.searchController.searchBar sizeToFit];
self.searchController.searchBar.showsScopeBar = YES;
[self.searchController.searchBar sizeToFit];
}];
(I'm still working on how to workaround the layout issues following an interface orientation change while the search bar is active - that still ends up overlapped.)
In the radar that Ray Wenderlich filed, #benck posted this answer from WWDC, which, if I'm not mistaken, hasn't been posted yet.
Per your comments, your UISearchController's UISearchBar has been assigned to your UITableView's tableHeaderView. In iOS 11, you should instead be assigning your UISearchController to the searchController property of your view's navigationItem. You no longer need to assign the UISearchBar anywhere. See Apple's documentation on this new property.
I met the same issue on my app, my solution is in iOS 11, using apple suggested new way for searchBar which is in navigationItem, otherwise, using the old way. My code in viewDidLoad() as below:
if #available(iOS 11.0, *) {
navigationController?.navigationBar.prefersLargeTitles = false
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
searchViewHeight.constant = 0
} else {
searchView.addSubview(searchController.searchBar)
}
I have two IBOutlets: searchView and searchViewHeight:
#IBOutlet var searchView: UIView!
#IBOutlet var searchViewHeight: NSLayoutConstraint! // new added for iOS 11
Before iOS 11, my viewController's hierarchy as below:
I have a searchView which height is 44 to contains my searchController's searchBar view. It's under navigation bar.
In iOS 11, I add a new IBOutlet for searchView's height constraint, and set its constant to 0, hide this container view. And add searchController as a part of navigation item.
See apple's document:
https://developer.apple.com/documentation/uikit/uinavigationitem/2897305-searchcontroller
One more thing is under iOS 11, the searchBar's textField background color is little darker than navigation bar color by default. For consistency, you can change it to white, the below code will work both for iOS11 and its prior:
if let textField = searchController.searchBar.value(forKey: "searchField") as? UITextField {
if let backgroundView = textField.subviews.first {
// Search bar textField background color
backgroundView.backgroundColor = UIColor.white
// Search bar textField rounded corner
backgroundView.layer.cornerRadius = 10
backgroundView.clipsToBounds = true
}
}
I think that the solution is to add the Search Bar in the Navigation Bar:
navigationController?.navigationBar.prefersLargeTitles = true // Navigation bar large titles
navigationItem.title = "Contacts"
navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white]
navigationController?.navigationBar.barTintColor = UIColor(displayP3Red: 0/255, green: 150/255, blue: 136/255, alpha: 1.0)
let searchController = UISearchController(searchResultsController: nil) // Search Controller
navigationItem.hidesSearchBarWhenScrolling = false
navigationItem.searchController = searchController
You can find an example for UISearchBarController - SearchBar and scope buttons overlap here.
I had the same issue in iOS 11.
Contrary to some of the comments here, if I look at your screenshots you DONT want to set it as the navigationItem because you don't have a UINavigationController setup.
Neither do you want to add the searchBar in the header of the tableView because for some reason it can't cope with the scopeBar
So what I did to fix it:
To get a UISearchBar with scopes over your tableView, use a UIViewController in interface builder not a UITableViewController.
Place a UISearchBar and a UITableView inside the view controller and wire them up properly (delegates, dataSource, etc).
Don't forget to change your swift file to UIViewController instead of UITableViewController as well and change it accordingly. (add a tableView property and connect it via IBOutlet, change the delegates for the tableView etc)
Then in interface builder, use autoLayout guides so the searchBar sits on top of the tableView
In interface builder when you activate the scope bar it will look totally weird but don't panic, it will be fine. I guess Apple screwed the rendering n interface builder when they changed the behavior to work with UINavigationController... anyway...
Then everything works as it should and look like this (in my case I present it the vc in a popover but that doesn't matter)
How can I show a UISearchBar in the NavigationBar?
I can't figure out how to do this.
Your help is very much appreciated.
To put searchBar into the center of navigationBar:
self.navigationItem.titleView = self.searchBarTop;
To put searchBar to the left/right side of navigationBar:
UIBarButtonItem *searchBarItem = [[UIBarButtonItem alloc] initWithCustomView:searchBar];
self.navigationItem.rightBarButtonItem = searchBarItem;
As of iOS 7, the UISearchDisplayController supports this by default. Set the UISearchDisplayController's displaysSearchBarInNavigationBar = YES to get this working easily.
Per the documentation:
Starting in iOS 7.0, you can use a search display controller with a navigation bar (an instance of the UINavigationBar class) by configuring the search display controller’s displaysSearchBarInNavigationBar and navigationItem properties.
As one commenter noted, using searchDisplayController.displaysSearchBarInNavigationBar = true ends up hiding any existing left/right bar button items.
I've found two different ways of adding a searchBar to a navigationBar using iOS7's new property on searchDisplayController.
1) Nib Based Approach
If you're using a .xib, you can set a User Defined Runtime Attribute for this value and for whatever reason, the leftBarButtonItem stays in tact. I have not tested it with a rightBarButtonItem.
2) Code (Timing Matters)
If you want to implement in code, timing seems to matter. It seems that you must add the searchBar to the navigationBar first, then set your barButtonItem.
- (void)viewDidLoad
{
...
self.searchDisplayController.displaysSearchBarInNavigationBar = true;
self.navigationItem.leftBarButtonItem = [UIBarButtonItem new];
...
}
Check out Apple's UICatalog sample code. It shows how to use the new UISearchController in three different ways: modally, in nav bar, and below the navigation bar.
Objective C code snippet for UISearchBar in NavigationBar
- (void)viewDidLoad {
UISearchController *searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
if (#available(iOS 11.0, *)) {
self.navigationItem.searchController = searchController;
} else {
self.navigationItem.titleView = searchController.searchBar;
}
}
Read more here
I have a search bar as a title view for my navigation bar.
And it looks like this, the way I want it to look like:
But when I tap on it, it just slides to top and becomes inaccessible
Here is the code I used to configure it:
- (void)configureSearchBar
{
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchBar.delegate = self;
self.navigationItem.titleView = self.searchController.searchBar;
}
Is there any way to fix this kind of problem?
self.searchController.hidesNavigationBarDuringPresentation = NO
Adding this line has solved this problem or me. The reason of this problem was that my search bar was set as a title view for my navigation bar and the property hidesNavigationBarDuringPresentation was set to YES by default. Setting this property to NO solves this kind of problem.
I added a navigation control to switch between views in my app. But some of the views shouldn't have 'Back' (the previous title) button. Any ideas about how to hide the back button?
Objective-C:
self.navigationItem.hidesBackButton = YES;
Swift:
navigationItem.hidesBackButton = true
The best way is to combine these, so it will hide the back button even if you set it up manually :
self.navigationItem.leftBarButtonItem=nil;
self.navigationItem.hidesBackButton=YES;
hide back button with bellow code...
[self.navigationItem setHidesBackButton:YES animated:YES];
or
[self.navigationItem setHidesBackButton:YES];
Also if you have custom UINavigationBar then try bellow code
self.navigationItem.leftBarButtonItem = nil;
In Swift:
Add this to the controller
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.setHidesBackButton(true, animated: false)
}
Use the code:
self.navigationItem.backBarButtonItem=nil;
In the function viewDidLoad of the UIViewController use the code:
self.navigationItem.hidesBackButton = YES;
Don't forget that you need to call it on the object that has the nav controller. For instance, if you have nav controller pushing on a tab bar controller with a RootViewController, calling self.navigationItem.hidesBackButton = YES on the RootViewController will do nothing. You would actually have to call self.tabBarController.navigationItem.hidesBackButton = YES
Add this code in your view controller
UIView *myView = [[UIView alloc] initWithFrame: CGRectMake(0, 0, 300, 30)];
UIBarButtonItem *btnL = [[UIBarButtonItem alloc]initWithCustomView:myView];
self.navigationItem.leftBarButtonItem = btnL;
Don't forget that we have the slide to back gesture now. You probably want to remove this as well. Don't forget to enable it back again if necessary.
if ([self.navigationItem respondsToSelector:#selector(hidesBackButton)]) {
self.navigationItem.hidesBackButton = YES;
}
if ([self.navigationController respondsToSelector:#selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
For me none of the above seemed to work, It had no visual effect. I am using storyboards with a view that is "embedded" in a navigation controller.
I then at code level add my menuItems and for some reason the "backButton" is visible when visually debugging the view hierarchy, and my menuItem Icon is displayed beneath the invisible "back button".
I tried the settings, as suggested at the various hook methods and that had no effect. Then I tried a more brutal approach and iterate over the subview which also had no effect.
I inspected my icon sizes and appeared to be ok.
After referring to he apple Human Interface Guideline I confirmed my Icons are correct. (1 pixel smaller in my case 24px 48px 72px).
The strangest part then is the actual fix...
When adding the BarButton Item give it a title with at least one character, In my case a space character.
Hopes this helps someone.
//left menu - the title must have a space
UIBarButtonItem *leftButtonItem = [[UIBarButtonItem alloc] initWithTitle:#" " <--THE FIX
style:UIBarButtonItemStylePlain
target:self
action:#selector(showMenu)];
leftButtonItem.image = [UIImage imageNamed:#"ic_menu"];
[self.navigationItem setLeftBarButtonItem:leftButtonItem];
It wasn't working for me in all cases when I set
self.navigationItem.hidesBackButton = YES;
in viewWillAppear or ViewDidLoad, but worked perfectly when I set it in init of the viewController.
try this one -
self.navigationController?.navigationItem.hidesBackButton = true
In c# or Xamarin.ios,
this.NavigationItem.HidesBackButton = true;
navigationItem.leftBarButtonItem = nil
navigationItem.hidesBackButton = true
if you use this code block inside didLoad or loadView worked but not worked perfectly.İf you look carefully you can see back button is hiding when your view load.Look's weird.
What is the perfect solution?
Add BarButtonItem component from componentView (Command + Shift + L) to your target viewControllers navigation bar.
Select BarButtonItem set Title = " " from right panel
self.navigationItem.setHidesBackButton(true, animated: true)