iOS11 UISearchBar missing in UINavigationBar when

2020-03-30 05:59发布

问题:

Strange things seem to happen when using the new iOS 11 navigationItem.searchController method on a detail view of a UISplitViewController.

The searchBar partly appears as a blank space on the first presentation, then appears in the wrong UITableViewController, but corrects itself after a few push and pops of UITableViewController.

I used to put the searchBar in the tableHeaderView, but I changed the code according to the WWDC recommendation:

if (@available(iOS 11.0, *)) {
    self.navigationItem.searchController = self.searchController;
    self.navigationItem.hidesSearchBarWhenScrolling = NO;
} else {
    self.tableView.tableHeaderView = self.searchController.searchBar;
}

This example is using standard sample code (default project for UISplitViewController and the Apple demo of UISearchController updated for iOS 11 (using a single UITableViewController)).

The initial view containing the searchController looks like this:

And clicking a UITableView item yields this:

However after clicking on a UITableView item and returning twice - it looks as it should:

and:

I was trying to determine why the Apple example for UISearchController worked and my code didn't. The main difference was it was embedded in UISplitViewController in the Detail View. Which means if shown in Compact mode has an extra UINavigationController in the stack. I found if my seque avoided the extra UINavigationController - it works correctly (but breaks device rotation). Similarly change the segue to modal allows it to work.

I note this is similar to this old question: UISplitViewController with new UISearchController issue with UISearchBar

I have created a sample project that demonstrates the problem (sample code: searchControllerDemo)

I'm stumped as to what is going on. So any help would be very much appreciated.

回答1:

It's been a while since this erupted but thought to leave a note here for whoever will face the same issue...

On compact width devices, upon segueing from master to detail, the detail navigation controller is on top of the master view controller, unlike regular width where the two navigation controllers have their own separate root view controllers.

So, the UINavigationController of the detail view controller needs to be removed upon segue in combact width devices using UISplitViewControllerDelegate method: splitViewController(_:showDetail:sender:)

func splitViewController(_ splitViewController: UISplitViewController, showDetail vc: UIViewController, sender: Any?) -> Bool {
    if splitViewController.isCollapsed, let navController = vc as? UINavigationController {
        if let detailVC = navController.topViewController {
            splitViewController.showDetailViewController(detailVC, sender: sender)
            return true
        }
    }
    return false
}