0

I have a UISearchController above a UITableView, popping up from a UIButton on a UIViewController.

All was well. Then iOS 11.0 came and a different set-up was needed. And then iOS 13.0 came out and the UISearchBar wasn't visible in the UI. I've added a special-case: the search bar is now visible. But there is a gap between the bottom of the search bar and the top of the table. A user can scroll table rows up to fill this gap and back down to reveal the gap.

How can I get rid of this gap?

Code:

        if #available(iOS 13.0, *) {
            // my attempt at getting a correct setup
            self.navigationItem?.searchController = searchController
            table.tableHeaderView = searchController?.searchBar
        } else if #available(iOS 11.0, *) {
            self.navigationItem = navigationItem
        } else {
            table.tableHeaderView = searchController?.searchBar
        }
Carl
  • 2,896
  • 2
  • 32
  • 50
  • Hi Carl, check out this link - https://stackoverflow.com/questions/57521967/ios-13-strange-search-controller-gap and let me know if it is helpful. – shbedev Nov 13 '19 at 16:20
  • hi @Sam I saw that post. tried the answers with votes without it addressing my problem. At this point I'd like to understand how Apple intends setup to work rather than a hack around Apple's APIs. – Carl Nov 13 '19 at 16:24

1 Answers1

0

The working solution came down to a timing issue of making the searchController the first responder.

The code in the question could be reduced back to:

if #available(iOS 11.0, *) {
    self.navigationItem = navigationItem
} else {
    table.tableHeaderView = searchController?.searchBar
}

as no special-case for iOS 13 was required.

I have a function to display the search controller and results and this was:

// be the last claiming firstResponder otherwise,
// keyboard doesn't appear and searchBar doesn't move into navbar
DispatchQueue.main.async {
    self.searchController?.searchBar.becomeFirstResponder()
}

This async made sense to me as the UI needed to complete before trying to set focus on the searchBar.

For iOS 13 (and this change is still compatible with iOS 11+) I've switched to asyncAfter

DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
    self.searchController?.searchBar.becomeFirstResponder()
}

This makes me nervous because I don't know why the code needs to wait 0.01seconds before calling becomerFirstResponder(). This is the only async call in this part of my code.

If anyone knows the why please answer and that will truly be the correct answer! :)

Carl
  • 2,896
  • 2
  • 32
  • 50