Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Display UISearchController's searchbar programmatically

Note 1: This question pertains to adding a UISearchController's search bar outside of the table view it updates - NOT as the table view's header.

Note 2: Some trial and error led me to a solution. Please see my answer below.

I am new to iOS development and am struggling to work with the UISearchController class. I have a view controller, and in my view controller's view, I plan to have a search bar above a table view. I would like the search bar to be linked to a UISearchController. Since interface builder does not come with a UISearchController, I am adding the controller programmatically. After instantiating a UISearchController, I have tried to add the search controller's search bar to my view programmatically but have not been successful. I have tried setting the search bar's frame and giving it autolayout constraints, but neither approach has worked for me (i.e. when I run the app, nothing appears). Here is the latest code I have tried:

    let searchController = UISearchController(searchResultsController: nil)

    // Set the search bar's frame
    searchController.searchBar.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 50)

    // Constraint to pin the search bar to the top of the view
    let topConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
    searchController.searchBar.setTranslatesAutoresizingMaskIntoConstraints(false)

    self.view.addSubview(searchController.searchBar)

    self.view.addConstraint(topConstraint)

Any help would be greatly appreciated! Thank you!

EDIT: Using only one of either setting the search bar's frame or you giving it autolayout constraints (as opposed to a combination both as I initially tried) appears to work at first, but after tapping on the search bar you will have issues as pointed out by Dwight. I've left the code for these cases in case it's helpful to compare to what you currently have, but for a working solution see my answer below.

Using autolayout constraints:

    let searchController = UISearchController(searchResultsController: nil)

    let topConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: (statusBarHeight + navigationBarHeight!))
    let leftConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 0)
    let rightConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 0)
    let heightConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 44)
    searchController.searchBar.setTranslatesAutoresizingMaskIntoConstraints(false)

    searchController.searchBar.addConstraint(heightConstraint)

    self.view.addSubview(searchController.searchBar)

    self.view.addConstraints([topConstraint, leftConstraint, rightConstraint])

I've set the topConstraint constant to the height of the status bar plus the height of the navigation bar, as my view controller is embedded in a navigation controller.

Adjusting the frame:

    let searchController = UISearchController(searchResultsController: nil)

    searchController.searchBar.frame = CGRect(x: 0, y: (statusBarHeight + navigationBarHeight!), width: self.view.frame.size.width, height: 44)

    self.view.addSubview(searchController.searchBar)
like image 831
kcstricks Avatar asked Jul 08 '15 04:07

kcstricks


1 Answers

After some more trial and error, I have the following working solution:

  1. Open up Main.storyboard and add to your view controller a UIView with height 44 (default height of a UISearchBar) and a UITableView. Set the autolayout constraints so that the UIView is pinned to the two sides and to the top layout guide (using the top layout guide ensures this will work whether or not your view controller is embedded in a navigation controller) and the table view is pinned to the two sides, the bottom layout guide, and its top pinned to the bottom of the UIView.
  2. Connect the UIView and UITableView as IBOutlets in your ViewController.swift. In my project, I called them topView and tableView.
  3. Declare a search controller at the top of your ViewController.swift: var searchController: UISearchController!
  4. Then, in viewDidLoad(), you will need:

    // Initialize and set up the search controller
    self.searchController = UISearchController(searchResultsController: nil)
    self.searchController.searchResultsUpdater = self
    self.searchController.dimsBackgroundDuringPresentation = false // Optional
    self.searchController.searchBar.delegate = self
    
    // Add the search bar as a subview of the UIView you added above the table view
    self.topView.addSubview(self.searchController.searchBar)
    // Call sizeToFit() on the search bar so it fits nicely in the UIView
    self.searchController.searchBar.sizeToFit()
    // For some reason, the search bar will extend outside the view to the left after calling sizeToFit. This next line corrects this.
    self.searchController.searchBar.frame.size.width = self.view.frame.size.width
    

This should be it! Of course, you'll need to make your view controller a UITableViewDatasource, UITableViewDelegate, UISearchBarDelegate, UISearchControllerDelegate, and UISearchResultsUpdating and take care of all required delegate methods as well, but as far as the search bar goes, this has worked for me. Please comment if you have any issues.

like image 118
kcstricks Avatar answered Oct 20 '22 02:10

kcstricks