I am trying to get the new iOS-11 searchBar approach to work, but don't manage. The searchBar shows up, but is shown below the left bar button, instead of next to it:
It is the same in landscape mode.
The code that I am using is:
self.searchResults = [[SearchResultsTable alloc] init];
self.searchResults.delegate = self;
searchController = [[UISearchController alloc] initWithSearchResultsController:self.searchResults];
searchController.searchResultsUpdater = self.searchResults;
searchController.hidesNavigationBarDuringPresentation = NO;
self.definesPresentationContext = YES;
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
target:self
action:#selector(swapToListView:)];
if ([self.navigationItem respondsToSelector:#selector(setSearchController:)]) {
// only available from IOS-11 onwards
self.navigationItem.title = nil;
self.navigationItem.titleView = nil;
[self.navigationItem setSearchController:searchController];
} else {
// Fallback on earlier versions
self.navigationItem.titleView = searchController.searchBar;
}
The old code works fine on pre-iOS-11 systems, but has other problems on iOS-11, so I prefer to use the new approach.
Anybody knows what I am doing wrong here?
If you want to put search bar next to left navigation item then make your search bar navigationItem's titleView regardless of iOS version, and don't use UINavigationItem's searchController property.
Related
iOS 11 I'm having a UITableViewController with a UISearchController on the table's headerview using the following code :
if(searchController == nil)
{
searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
searchController.dimsBackgroundDuringPresentation = false;
searchController.searchResultsUpdater = self;
searchController.searchBar.delegate = self;
self.definesPresentationContext = NO;
searchController.delegate = self;
}
self.tableView.tableHeaderView = searchController.searchBar;
[self.tableView setContentOffset:CGPointMake(0,searchController.searchBar.bounds.size.height) animated:YES];
When I run the app, the behavior I want is perfectly working for the tableview with rows more than the height of the device screen but on the case of tableview having only a few number of rows, the search bar is dropping a little bit down from the navigation bar.
When there are few cells on the tableview, the search bar drops down as in this picture
When there are more cells on the tableview, the search bar doesn't drop down
On iOS 11 the behaviour of UISearchController with tableView header has changed, now it a part of the navigationItem and you dont need the tableView. So you must check if iOS >= 11 and do the following
if (#available(iOS 11.0, *)) {
self.navigationItem.searchController = searchController;
// ToDo : dont forget to hide the tableView
// ...
} else {
self.tableView.tableHeaderView = searchController.searchBar;
[self.tableView setContentOffset:CGPointMake(0,searchController.searchBar.bounds.size.height) animated:YES];
}
In my app, I have a navigation controller (N1), controlling a tableview controller (T1) with a search bar.
When the search bar becomes active, a new navigation controller (N2) is presented from the storyboard to display the search results. (see image)
This worked perfectly fine, until iOS 11, where the search bar is moved from the tableview header to the navigation bar.
A partial solution is to differentiate between OS versions, as follows:
-(void)initSearchController{
UINavigationController *searchResultsController = [[self storyboard] instantiateViewControllerWithIdentifier:#"TableSearchResultsNavController"];
self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];
self.searchController.searchResultsUpdater = self;
self.searchController.hidesNavigationBarDuringPresentation = NO;
if (#available(iOS 11.0, *)) {
self.navigationItem.searchController = self.searchController;
//searchResultsController.navigationItem.searchController = self.searchController;
} else {
self.tableView.tableHeaderView = self.searchController.searchBar;
}
}
However, because of the new position of the search bar in iOS 11, as soon as the search results are displayed, the search box disappears, since it is part of the navigation bar that has been replaced by the alien storyboard navcontroller.
I also modified a method, that is called when the search bar becomes active, as follows, but still the search bar disappears:
// Called when the search bar becomes first responder
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
NSString *searchString = self.searchController.searchBar.text;
[self updateFilteredContentForSearchString:searchString];
if (self.searchController.searchResultsController) {
UINavigationController *navController = (UINavigationController *)self.searchController.searchResultsController;
SearchResultsTableViewController *vc = (SearchResultsTableViewController *)navController.topViewController;
self.searchController.dimsBackgroundDuringPresentation = false;
//my attempt, to no avail
if (#available(iOS 11.0, *)) {
vc.navigationItem.searchController = self.searchController;
} else {
vc.searchController=self.searchController;
}
vc.searchResults = self.searchResults;
[vc.tv reloadData];
}
}
What would be the approach to solve this? I want the app to remain compatible with pre-11 OS's (at least iOS10).
Do I have to completely rework this mechanism (if yes, how?), or is there just a simple line of code that would simply tell the controller N2 to also display the search bar?
Thanks for your insights
I have multiple view controllers which all use one class (we'll call it searchClass <NSObject>) I wrote that has a UISearchController for searching an external API. The user can tap the search icon and the search controller becomes active: [_searchClass.searchController setActive:YES]; It uses its own table view controller (not the one in each of the view controllers, because they aren't all table view controllers).
In my case I make the search bar appear in the navigation bar. Search works great, the user can select a search result and tap it for a detail view. The problem is when the user goes back (unwinds) from the detail view to the search results, there is a black gap about 44 pts tall that appears briefly above the table view and below the navigation bar, and then disappears.
Here is my setup. In the view controller:
self.definesPresentationContext = YES;
_searchClass = [SearchClass new];
_searchClass.navController = [self navigationController];
In the search class:
_searchTableViewController = [[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:#"searchTableViewController"];
_searchTableViewController.tableView.delegate = self;
_searchTableViewController.tableView.dataSource = self;
_searchTableViewController.tableView.backgroundColor = [UIColor clearColor];
_searchTableViewController.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
_searchTableViewController.tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectZero];
_searchTableViewController.definesPresentationContext = YES;
_searchController = [[UISearchController alloc] initWithSearchResultsController:_searchTableViewController];
_searchController.delegate = self;
_searchController.hidesNavigationBarDuringPresentation = NO;
_searchController.searchBar.delegate = self;
_searchController.searchBar.searchBarStyle = UISearchBarStyleMinimal;
_searchController.searchBar.showsCancelButton = YES;
_searchController.searchBar.frame = CGRectMake(self.searchController.searchBar.frame.origin.x, self.searchController.searchBar.frame.origin.y, self.searchController.searchBar.frame.size.width, 44.0);
There are also the usual delegate methods for UISearchBar and UISearchController, and the code that displays the search bar, which uses an animation to replace the titleView of the navigation bar.
How do I get rid of that gap after unwinding back to the search results?
I found the solution, it's related to the UINavigationBar. For some reason setting the translucent property to NO seems to have caused this issue.
self.navigationBar.translucent = YES;
Setting it to YES (or omitting the line since it is the default) made it work properly. Since I still wanted to have the navigation bar be opaque, I did the following to make the nav bar translucent only during transitions, which seems to be where the issue lies:
- (void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
self.navigationController.navigationBar.translucent = YES;
}
-(void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.navigationController.navigationBar.translucent = NO;
}
Definitely seems like a genuine iOS bug to me.
I added a UISearchBar to my initial UIViewController and everything works fine. However when I go to add the same UISearchBar, the same way to another ViewController that's pushed ontop of the first one, nothing seems to happen when I click into the searchBar. No delegate method is fired, no keyboard comes up, nothing.
This is how I'm adding it to the navigationBar:
- (void)viewDidLoad {
[super viewDidLoad];
UITableViewController *searchResultsController = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
searchResultsController.tableView.dataSource = self;
searchResultsController.tableView.delegate = self;
self.searchResults = [NSMutableArray array];
self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];
self.searchController.searchResultsUpdater = self;
self.searchController.hidesNavigationBarDuringPresentation = NO;
self.searchController.searchBar.placeholder = NSLocalizedString(#"Search, eh?", nil);
// Include the search bar within the navigation bar.
self.navigationItem.titleView = self.searchController.searchBar;
self.definesPresentationContext = YES;
}
Like I said it works in the first UIViewController, am I missing something in the other 2-3 viewControllers I've tried adding this too? I don't see why the searchBar shows up in the navBar but nothing is happening upon clicking into it. I've also set the delegate like so:
#interface ViewController () <UISearchResultsUpdating>
Try setting definesPresentationContext to NO on the first view controller as soon as you present a new one on.
I believe that the presentation walks up the view controller hierarchy looking for the first one that defines a context and not down.
There is plenty of sample code out there, and I thought I was following it line for line; my code:
(void)viewDidLoad
{
[super viewDidLoad];
// init search bar
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
searchBar.delegate = self;
searchBar.showsCancelButton=YES;
// set up searchDisplayController
UISearchDisplayController *searchController = [[UISearchDisplayController alloc]
initWithSearchBar:searchBar contentsController:self];
searchController.delegate = self;
searchController.searchResultsDataSource = self;
searchController.searchResultsDelegate = self;
// display search bar in nav bar
self.searchDisplayController.displaysSearchBarInNavigationBar = YES;
}
With that code, shouldn't I see the search bar displayed in the navigation bar? All I see in the nav bar is the cancel button. I have declared the protocols <UISearchDisplayDelegate, UISearchBarDelegate> in my header file. What am I missing, or what could be going wrong? Thanks
Note:
Using self.navigationItem.titleView = searchBar, the search bar displays as expected. I wonder what are the advantages of the newer displaysSearchBarInNavigationBar method..
-- Edit by tassilo --
It looks like the search bar is added to the navigation bar, but then disappears.
The displaysSearchBarInNavigationBar property makes it so the search bar slides into the navigation bar when the user taps it, like what happens in the Apple Mail app. You still need to add the search bar to the view somewhere.
Best way to do this is to set the tableHeaderView of a UITableViewController to the search bar.
self.tableView.tableHeaderView = self.searchBar;
This line is your problem.
self.searchDisplayController.displaysSearchBarInNavigationBar = YES;
self.searchDisplayController is not the same as searchDisplayController, that you created.
So just replace self.searchDisplayController with searchDisplayController. Also, be sure that you don't have #synchronize searchDisplayController;