How do I use UISearchController in iOS 8 where the UISearchBar is in my navigation bar and has scope buttons?

Doug Smith picture Doug Smith · Jan 10, 2015 · Viewed 18.7k times · Source

I'm trying to use the new UISearchController from iOS 8, and embed its UISearchBar in my UINavigationBar. That's easily done as follows:

searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.delegate = self
searchController.searchBar.delegate = self
searchController.dimsBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = false
navigationItem.titleView = searchController.searchBar

But when I add the scope buttons:

searchController.searchBar.showsScopeBar = true
searchController.searchBar.scopeButtonTitles = ["Posts, Users, Subreddits"]

It adds the buttons behind the UISearchBar and obviously looks very odd.

How should I be doing this?

Answer

user4151918 picture user4151918 · Jan 17, 2015

You're bumping into a "design issue" where the scopeBar is expected to be hidden when the searchController is not active.

The scope bar buttons appear behind (underneath) the search bar since that's their location when the search bar becomes active and animates itself up into the navigation bar.

When the search is not active, a visible scope bar would take up space on the screen, distract from the content, and confuse the user (since the scope buttons have no results to filter).

Since your searchBar is already located in the titleView, the (navigation and search) bar animation that reveals the scope bar doesn't occur.

  • The easiest option is to locate the search bar below the navigation bar, and let the searchBar animate up into the title area when activated. The navigation bar will animate its height, making room to include the scope bar that was hidden. This will all be handled by the search controller.
  • The second option, almost as easy, is to use a Search bar button icon, which will animate the searchBar and scopeBar down into view over the navigation bar.

    - (IBAction)searchButtonClicked:(UIBarButtonItem *)__unused sender {
        self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
        self.searchController.searchResultsUpdater = self;
        self.searchController.hidesNavigationBarDuringPresentation = NO;
        self.searchController.dimsBackgroundDuringPresentation = NO;
        self.definesPresentationContext = YES;
        self.searchController.searchBar.scopeButtonTitles = @[@"Posts", @"Users", @"Subreddits"];
        [self presentViewController:self.searchController animated:YES completion:nil];
    }
  • If you want the searchBar to remain in the titleView, an animation to do what you want is not built in. You'll have to roll your own code to handle the navigationBar height change and display your own scope bar (or hook into the internals, and animate the built-in scopeBar down and into view).

    If you're fortunate, someone else has written willPresentSearchController: code to handle the transition you want.

  • If you want to always see a searchBar and scopeBar, you'll probably have to ditch using the built-in scopeBar, and replace it with a UISegmentedControl which the user will always see, even when the search controller is not active.

Update:

This answer suggested subclassing UISearchController to change its searchBar's height.