5

I'm trying to add a UISearchController to a UIViewController that contains a UITableView (and an MKMapView too, but hopefully that's not the problem). I followed Ray Wenderlich's tutorial but I can't get the same result in terms of behaviour.

Here is my viewDidLoad:

override func viewDidLoad() {
        super.viewDidLoad()

        // Setup the Search Controller
        searchController.searchResultsUpdater = self
        searchController.obscuresBackgroundDuringPresentation = false
        searchController.searchBar.placeholder = NSLocalizedString("Search references by project, customer or city", comment: "")
        if #available(iOS 11.0, *) {
            navigationItem.searchController = searchController
            navigationItem.hidesSearchBarWhenScrolling = true
        } else {
            tableView.tableHeaderView = searchController.searchBar
        }
        definesPresentationContext = true

        self.modeSelector.layer.cornerRadius = 5.0

        if let split = splitViewController {
            let controllers = split.viewControllers
            detailViewController = (controllers[controllers.count - 1] as! UINavigationController).topViewController as? ReferenceViewController
        }

        self.navigationItem.rightBarButtonItem?.isEnabled = false
    }

Note that the #available test in the middle is because I need to support iOS up to 9.1.

Now I see several problems:

  • The search bar appears right away and I can't hide it by scrolling
  • When I focus the search bar, the top of the tableview doesn't stick to the bottom of the navigation item:

enter image description here

The only major difference I see with Ray Wenderlich's sample project is that since I created my project with Xcode 9, my storyboard doesn't use top and bottom layout guides, but safe areas. Don't know if it's relevant, but that's the only thing I see.

Any idea what's going on and how I could fix this?

shim
  • 9,289
  • 12
  • 69
  • 108
Sebastien
  • 3,583
  • 4
  • 43
  • 82

3 Answers3

6

If you need to support iOS up to 9.1, you probably use emulator with version older than 9.1. Therefore, "maybe" obscuresBackgroundDuringPresentation doesn't affect the searchController properly, since it's only available on iOS 9.1 or newer. Add dimsBackgroundDuringPresentation to support up to 9.1:

if #available(iOS 9.1, *) {
    searchController?.obscuresBackgroundDuringPresentation = false
} else {
    searchController?.dimsBackgroundDuringPresentation = false
}

If this doesn't help to display as expected, I'm almost sure that the problem is about your layout constraints. Please add your current constraints if you couldn't bring your layout in compliance with safe area.

Dorukhan Arslan
  • 2,676
  • 2
  • 24
  • 42
  • This "if available" didn't change anything but I had a look at the constraints and I did find something weird in IB: the top constraint of my tableView was like this: - Table View.Top Equal Superview.Top - Constant: 0 If I change this to: - Table View.Top Equal Safe Area.Top - Constant: 0 It seems to give me the expected layout, even though on iOS 11, when I activate the search bar, the table view waits for the end of the search bar animation to go to its right location. But that's good enough. Now I just have to figure out why the search bar appears by default. – Sebastien Dec 03 '17 at 08:32
  • 1
    Adding the constraint "Align Top to: Safe Area - Constant = 0" to your table does wonders in this case for sure. :) What you want next? If you still can't figure out that issue, may you provide some more screenshots to show your current progress? – Dorukhan Arslan Dec 04 '17 at 08:27
  • 1
    I ended up switching back to the tableHeaderView strategy since I want to switch between a table and a map view for the same data in this controller, and I don't want to show the search bar in map mode. With that and the layout top aligned to the safe area, I still have a slight bug on iPhone X but none of my customers have that so it's OK. – Sebastien Dec 04 '17 at 16:16
3

use this below line of code into your viewDidload

self.navigationController?.navigationBar.isTranslucent = false

Hope this will help you

Ganesh Manickam
  • 2,113
  • 3
  • 20
  • 28
  • Thanks. Now in iOS 11, the top of the table view sticks to the bottom of the navigation bar. But the search bar is still displayed by default and it still stays there when I scroll. – Sebastien Nov 24 '17 at 13:11
  • Plus, when I do that, it screws up all the other view controllers I push after that one. – Sebastien Nov 24 '17 at 13:16
  • for remaining viewcontroller `self.navigationController?.navigationBar.isTranslucent = true` use – Ganesh Manickam Nov 24 '17 at 13:18
0

If you are using xcode 9 (ios 11). Then the thing you really want to do is - Use the new Broader navigation bars which are the new highlights in the ios 11 devices. But as there are many who have not shifted to ios-11, previous version devices are also taken into consideration. For adding the search bar to the newer navigation bars I have used the following function which gives a search bar on scrolling and hides it when user scrolls the page.

func addSearchBar() {
if #available(iOS 11.0, *) {
  let sc = UISearchController(searchResultsController: nil)
  sc.delegate = self
  let scb = sc.searchBar
  scb.tintColor = UIColor.white
  scb.barTintColor = UIColor.white
  //Change the colors as you like them
  if let textfield = scb.value(forKey: "searchField") as? UITextField {
    textfield.textColor = UIColor.blue
    if let backgroundview = textfield.subviews.first {

      // Background color
      backgroundview.backgroundColor = UIColor.white

      // Rounded corner
      backgroundview.layer.cornerRadius = 10;
      backgroundview.clipsToBounds = true;
    }
  }

  if let navigationbar = self.navigationController?.navigationBar {
    navigationbar.barTintColor = UIColor.white
  }
  navigationItem.searchController = sc
  navigationItem.hidesSearchBarWhenScrolling = true
}else{
//add the logic for previous version devices here.
}

I have also set the self.navigationController?.navigationBar.prefersLargeTitles = true; in viewDidLoad as there is a bug in xcode9 and setting it from the interface builder does not work(yet).

The following method has been taken from here