My UITableViewController is conforming to the new UISearchControllerDelegate and also UISearchResultsUpdating.
Here is my setup code for the search bar:
override func viewDidLoad() {
var searchController = UISearchController(searchResultsController: self)
searchController.searchResultsUpdater = self
self.tableView.tableHeaderView = searchController.searchBar
self.definesPresentationContext = true
}
However, when running this in the simulator there is no search bar in the table header, even though it is specified in the code. I also tried this code in viewWillAppear, but again no search bar was shown.
I was informed by an Apple Engineer that you must give the Search Bar a frame. If you print the frame of the search bar, you will notice it's height is zero. So this is probably a bug in Apple's code.
searchController.searchBar = CGRectMake(0.0, 0.0, 320.0, 44.0)
Edit:
The documentation specifies that you must pass in the View Controller that you want to display the results. To display this in the same View Controller you are in, pass in nil.
var searchController = UISearchController(searchResultsController: nil)
Related
Upgrading our application to support iPhone X. How can I add a search bar to the header of a table view and have it within the safe zone? Here is how we currently build the search bar.
let searchController = UISearchController(searchResultsController: nil)
func buildSearchBar() {
self.searchController.searchResultsUpdater = self
self.searchController.hidesNavigationBarDuringPresentation = false
self.searchController.dimsBackgroundDuringPresentation = false
self.searchController.searchBar.sizeToFit()
self.tableView.tableHeaderView = searchController.searchBar
self.definesPresentationContext = true
}
This topic is discussed explicitly in Building Apps for iPhone X video. (Designing for iPhone X also a good video.)
Bottom line, Apple suggests using navigation controller and showing it there:
let searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
if #available(iOS 11, *) {
navigationItem.searchController = searchController
searchController.isActive = true
} else {
present(searchController, animated: true)
}
(By the way, even in the absence of a navigation controller, present-ing the search controller, rather than setting it to be the table header, can prevent it from scrolling out of the safe area.)
Unclear what you mean by "within the safe zone". The table view can scroll, so the search bar is not necessarily "within" any part of the screen; it can be scrolled up behind the sensor area and on beyond.
You'll notice, however, that the native apps do not put the search bar as the header of the table. They put it in the navigation bar. You should do the same. Put the search bar into the navigation bar by setting the searchController of the navigationItem.
I'm trying to implement a UISearchController with it's searchBar inside the navigationBar of a UINavigationController. This navigationBar has translucent and all Extend Edges turned off in Interface Builder.
The setup is quite simple:
ViewControllerWithSearchController is embedded in a UINavigationController. My viewController code looks like this:
class ViewControllerWithSearchController: UIViewController, UISearchControllerDelegate, UISearchResultsUpdating, UISearchBarDelegate {
var searchController: UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
definesPresentationContext = true
initializeSearchController()
}
// MARK: - Search
func initializeSearchController() {
// Create and configure the UISearchController
searchController = UISearchController(searchResultsController: nil)
searchController.delegate = self
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.delegate = self
searchController.searchBar.sizeToFit()
searchController.hidesNavigationBarDuringPresentation = false
navigationItem.titleView = searchController.searchBar
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
// Check the frame of the view
print(view.frame)
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
// Some code here
}
}
When I run this, it works. The frame of the ViewController's view on initial run is (0.0, 64.0, 375.0, 603.0)
This viewController contains a button which pushes a generic viewController onto the stack. When I pop this viewController, the frame of the ViewControllerWithSearchController is unchanged (correct behavior).
However, when I activate the searchBar and then push and pop the second UIViewController (while the searchBar is active), the frame of ViewControllerWithSearchController gets set to (0.0, 0.0, 375.0, 667.0). The view gets extended below the navigationbar, even though this behavior is turned off.
All involved ViewControllers have their Extend Edges options turned off in InterfaceBuilder.
For now, I've implemented a workaround by turning on all the Extend Edges options. This creates a bit of overhead, so I'd rather not do it. Is there a better solution to solve this problem?
I've attached a sample project to illustrate the problem.
Sample project
I'm trying to keep the search bar in view as the table scrolls. At the moment I'm placing it as the header in a tableview, and it works as it should, but of course the search bar scrolls off screen as you go down the table. I thought I could do this simply modifying this code sample:
How do I use UISearchController in iOS 8 where the UISearchBar is in my navigation bar and has scope buttons?
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.delegate = self
searchController.searchBar.delegate = self
searchController.dimsBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = false
tableview.tableHeaderView = searchContoller.searchBar // How to put it elsewhere?
//Alternative that also works
navigationItem.titleView = searchController.searchBar
The idea was to take some other view and do
otherview = searchController.searchBar
For instance an outlet to a UISearchBar, or a blank UIView, or something like that.
But it doesn't show the searchBar if I do that. It seems to only work as the header view of a table or as a navigationItem.titleView.
Am I missing something?
If you have a blank UIView that is placed above the tableview.
let's assume you have an outlet to that blank UIView called searchContainer.
Then you can add the search bar of the UISearchController to that view by adding the following line
searchContainer.addSubview(searchController.searchBar)
I AM NOT USING STORYBOARD SEGUES.
When I use UISearchController to have a search bar at the top of my table view, I get extremely strange behavior. Is there documentation on how I'm supposed to handle the search bar when a view dismisses? When I switch to a new view controller via an animation or push one on a nav stack, the bar is stuck in its spot until I hit the "Cancel" button.
See a video of what's happening in this short clip:
https://www.youtube.com/watch?v=6G7xFMENm_o&feature=youtu.be
This is the code, in the view controller, that sets up search bar:
var s: UISearchController!
private func configureSearching() {
s = UISearchController(searchResultsController: nil)
s.searchResultsUpdater = self
s.dimsBackgroundDuringPresentation = false
s.searchBar.searchBarStyle = .Minimal
s.hidesNavigationBarDuringPresentation = false
tableView.tableHeaderView = s.searchBar
s.searchBar.sizeToFit()
}
you should add the following line in viewDidLoad
self.definesPresentationContext = true
I am relatively new to iOS (100 hours or so) and I am trying to implement a UISearchController without a storyboard. Is it possible to do this programmatically?
You have to implement UISearchController programmatically since Apple hasn't provided the ability to set it up using Storyboard yet.
Here are the steps to implement UISearchController in a view controller
Conform to UISearchResultsUpdating Protocol
Create a variable to reference the UISearchController
var searchController: UISearchController!
Set searchController in viewDidLoad(_:)
override func viewDidLoad() {
super.viewDidLoad()
searchController = UISearchController(searchResultsController: nil)
// The object responsible for updating the contents of the search results controller.
searchController.searchResultsUpdater = self
// Determines whether the underlying content is dimmed during a search.
// if we are presenting the display results in the same view, this should be false
searchController.dimsBackgroundDuringPresentation = false
// Make sure the that the search bar is visible within the navigation bar.
searchController.searchBar.sizeToFit()
// Include the search controller's search bar within the table's header view.
tableView.tableHeaderView = searchController.searchBar
definesPresentationContext = true
}
Implement the method updateSearchResultsForSearchController(_:), which is called when the search bar becomes the first responder or when the user makes changes to the text inside the search bar
func updateSearchResultsForSearchController(searchController: UISearchController) {
// No need to update anything if we're being dismissed.
if !searchController.active {
return
}
// you can access the text in the search bar as below
filterString = searchController.searchBar.text
// write some code to filter the data provided to your tableview
}