Search code examples
ios9uisearchbaruisearchcontroller

iOS9 Scope Bar appears either behind or beside Search Bar


I have a custom UITableViewController with a UISearchController set to the tableHeaderView as follows inside viewDidLoad():

    definesPresentationContext = true
    searchController.searchResultsUpdater = self
    searchController.searchBar.delegate = self
    searchController.dimsBackgroundDuringPresentation = false
    if #available(iOS 9.1, *) {
        searchController.obscuresBackgroundDuringPresentation = false
    }
    searchController.searchBar.barStyle = .Black
    searchController.searchBar.searchBarStyle = .Default
    searchController.searchBar.keyboardAppearance = .Dark
    searchController.searchBar.scopeButtonTitles = ["Title 1", "Title 2", "Title 3", "Title 3", "Title 3", "Title 3"]
    tableView.tableHeaderView = searchController.searchBar

When UITableViewController first loads, the scope bar is visible underneath the search bar and taking the whole width: enter image description here

After touching inside the search bar, the scope bar is shown beside the search bar: enter image description here

After hitting cancel, the search bar is shown properly without the scope bar underneath, although subsequence touches on the search bar still reveal the scope bar beside it: enter image description here

I've tried the following:

  • Changing searchBarStyle from .Minimal to .Default
  • Calling sizeToFit() on searchBar and tableHeaderView, tried in both viewDidLoad() and viewWillAppear()
  • Explicitly setting frame height of searchBar and tableHeaderView to 88 in viewWillAppear()
  • The proposed solutions here
  • Purging all builds, cleaning and rebuilding.

Nothing so far has made any difference whatsoever to the appearance or behavior. I want the scope bar below the search bar, and for it not to appear behind the search bar initially. Is UISearchController busted or I am just doing something dumb.


Solution

  • This is a bug in UISearchBar, you should create a radar for it.

    A workaround is to add some code AFTER you set scopeButtonTitles:

    UIView *scopeBarContainer = [[[searchController.searchBar.subviews firstObject] subviews] firstObject];
    for ( UIView *view in scopeBarContainer.subviews ) {
        if ( [view isKindOfClass:[UISegmentedControl class]] ) {
            scopeBarContainer.hidden = YES;
            break;
        }
    }