I have an App that is presenting a MKMapView embedded in a UINavigationController. In the UINavigationController I have put a UISearchController. When the User touch the UISearchController it displays a UITableViewController.
It works well while I'm not adding the Scope button in the UISearchController.
Here the screenshot of the UISearchController in the UINavigationController when I start the App.
Next when I touch the UISearchController, it displays the UITableViewController and scope button.
Here we can already see there's an issue with the scope button because they are not well integrated in the UISearchController (color should be translucent)
Next, when I touch the Cancel button to go back to the Main viewController, the UISearchController is not recovering its original style
it has a dark gray border (that probably comes from the scope button).
Here's how I add the UISearchController in the Main view Controller
func initSearchController() {
let mySearchController = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("SearchControllerId") as! SearchController
self.searchController = UISearchController(searchResultsController: mySearchController)
mySearchController.theSearchController = self.searchController
mySearchController.delegate = self
// Configure the UISearchController
self.searchController.searchResultsUpdater = self
self.searchController.delegate = self
self.searchController.searchBar.delegate = self
self.searchController.searchBar.placeholder = "data.."
self.searchController.hidesNavigationBarDuringPresentation = false
self.searchController.dimsBackgroundDuringPresentation = true
self.navigationItem.titleView = searchController.searchBar
self.definesPresentationContext = true
}
this method is called in the viewDidLoad() of my Main ViewController.
Next, when the SearchController is displayed, I'm adding the scope button with the following code in my TableViewController subclass
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// Mandatory to make sure the TableView is displayed when the search field is empty
// when user touch it.
view.hidden = false
var rect = delegate.searchController.searchBar.superview?.frame
rect?.size.height = 88
self.delegate.searchController.searchBar.scopeButtonTitles = ["one", "two", "three"]
self.delegate.searchController.searchBar.showsScopeBar = true
self.delegate.searchController.searchBar.superview?.frame = rect!
}
and the following code is executed when search is closed
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
var rect = delegate.searchController.searchBar.superview?.frame
rect?.size.height = 44
self.delegate.searchController.searchBar.superview?.frame = rect!
self.delegate.searchController.searchBar.showsScopeBar = false
self.delegate.searchController.searchBar.scopeButtonTitles = nil
}
As you can see I have severals issues with this code.
Scope buttons are not displayed correctly and I'm unable to add them with a nice animation
When user exits the search Scope buttons are removed but it impacts the background of the UISearchController
Can you tell me what I'm doing wrong and what should I do to integrate correctly Scope Button in UISearchController?.
I have found examples but only when the UISearchController is not embedded in the UINavigationController.
Thanks for your help!
Sébastien.
You should try using the searchBar.scopeButtonTitles in your instance of UISearchController:
func initSearchController() {
let mySearchController = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("SearchControllerId") as! SearchController
searchController = UISearchController(searchResultsController: mySearchController)
// Set Scope Bar Buttons
searchController.searchBar.scopeButtonTitles = ["one", "two", "three"]
// searchController.searchBar.showsScopeBar = true //if you want it always visible
// Configure the UISearchController
searchController.searchResultsUpdater = self
searchController.searchBar.sizeToFit()
tableView.tableHeaderView = searchController.searchBar
searchController.delegate = self
searchController.searchBar.delegate = self
searchController.searchBar.placeholder = "data.."
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = true
definesPresentationContext = true
}
No need to show or hide your scopeButtons in willAppear/didDisapear. This is set by: searchController.searchBar.showsScopeBar = true
Related
I have tableViewController at the storyboard.
I programmatically added searchController to the table header.
private func setupSearchView(){
if !showSearchBar { return }
let storyboard = UIStoryboard(name: "Search", bundle: nil)
resultViewController =
storyboard.instantiateViewController(withIdentifier: "NewSearchTableViewController") as? SearchResultTableViewController
searchController = UISearchController(searchResultsController: resultViewController)
resultViewController?.tableView.delegate = self
searchController.delegate = self
searchController.searchResultsUpdater = self
searchController.searchBar.delegate = self // Monitor when the search button is tapped.
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
tableView.tableHeaderView = searchController.searchBar
searchController.searchBar.sizeToFit()
searchController.searchBar.placeholder = "Search here...".localized
definesPresentationContext = true
}
When I selected the cell in the table and went to the details screen - it works perfectly.
But when I pressed button back, the search bar was scrolled under the navigation bar.
Normal behaiver
Bad behavior after button back pressed
I'm trying to show the UISearchController by tapping on the UIBarButtonItem. But the SearchBar appears behind the NavigationBar. If I set definesPresentationContext = false, then the SearchBar appears above the NavigationBar, but the transitions don't work.
#IBAction func searchButtonPressed(_ sender: Any) {
searchResultsController = self.storyboard?.instantiateViewController(withIdentifier: "SearchResultsController") as? SearchResultsController
searchResultsController.tableView.delegate = self
let searchController = UISearchController(searchResultsController: searchResultsController)
searchController.searchResultsUpdater = searchResultsController
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.autocapitalizationType = .words
definesPresentationContext = true
present(searchController, animated: true)
}
Before BarButtonItem tapped
After BarButtonItem tapped
View UI Hierarchy
Interface Builder
searchController.hidesNavigationBarDuringPresentation = false solve this problem, but I need the navigation bar to not be hidden
UPDATE:
Inserting the SearchBar inside the Navigation Bar is not suitable for my app
https://imgur.com/a/74e5sSk
If you are using UITableViewController then you can do the following:
let searchController = UISearchController(searchResultsController: nil)
searchController.obscuresBackgroundDuringPresentation = false
searchController.definesPresentationContext = true
Then, you need to assign this searchController to navigationItem:
self.navigationItem.searchController = searchController
Now searchbar is going to appear when you pull the tableview and will look this way:
If you want to keep the search bar permanently, then do this:
self.navigationItem.hidesSearchBarWhenScrolling = false
I showed UIViewController like modal style. UIViewController has UITableView. I added UISearchController to UITableView but UISearchController has incorrect behavior when it disappeared. I made many times UISearchControllers but I didn't face the this behavior.
My code
So I show the UIViewController
#objc fileprivate func selectInterlocutor(_ button: UIButton) {
let selectInterlocutorTVC = SelectInterlocutorTableViewController()
selectInterlocutorTVC.modalPresentationStyle = .overCurrentContext
selectInterlocutorTVC.modalTransitionStyle = .coverVertical
selectInterlocutorTVC.providesPresentationContextTransitionStyle = true
present(selectInterlocutorTVC, animated: true) {
}
}
I add UISearchController to tableView
fileprivate func addSearchController() {
searchController.searchBar.barStyle = .default
searchController.delegate = self
searchController.searchBar.delegate = self
searchController.searchResultsUpdater = self
searchController.searchBar.autocapitalizationType = .words
searchController.dimsBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.sizeToFit()
tableView.tableHeaderView = searchController.searchBar
}
Please look at this video that you can see this behavior.
https://www.dropbox.com/s/l3m3q8wmqoy3qv2/SearchBarBug.mov?dl=0
How can I fix it?
I removed UISearchController and I used UISearchBar and it works for me.
fileprivate func addSearchController() {
searchBar.barStyle = .default
searchBar.delegate = self
searchBar.autocapitalizationType = .words
searchBar.showsCancelButton = true
searchBar.sizeToFit()
tableView.tableHeaderView = searchBar
}
I have a problem when trying to add a search bar (UISearchController) on the header of the table of MasterViewController.
As you can see, the table is getting under the search bar.
Any ideas on how can I fix this?
Here is the code that I use for the MasterViewController
private var searchController : UISearchController = ( {
let controller = UISearchController(searchResultsController: nil)
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
return controller
})()
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.translucent = false
self.edgesForExtendedLayout = .None
self.extendedLayoutIncludesOpaqueBars = false
self.automaticallyAdjustsScrollViewInsets = false
searchController.searchResultsUpdater = self
searchController.searchBar.delegate = self
self.tableView.tableHeaderView = searchController.searchBar
if let split = self.splitViewController {
let controllers = split.viewControllers
self.detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
}
}
Open your storyboard, select your view controller and in attributes inspector, uncheck Under Top Bars in View Controller group
in my swift 2 app i have a table view with a search bar:
But if tap on the search bar, my navigation bar and the search bar will be hidden.
This is my code which is in the viewDidLoad
self.resultSearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
controller.hidesNavigationBarDuringPresentation = true
self.MyTable.tableHeaderView = controller.searchBar
return controller
})()
At the beginning i also get this message:
Attempting to load the view of a view controller while it is
deallocating is not allowed and may result in undefined behavior
()
My Question is, where is my mistake? :/
from this tutorial you can use this code to solve the problem.
self.navigationController!.navigationBar.translucent = false
searchController!.hidesNavigationBarDuringPresentation = false
// This makes the view area include the nav bar even though it is opaque.
// Adjust the view placement down.
self.extendedLayoutIncludesOpaqueBars = true
self.edgesForExtendedLayout = UIRectEdge.Top
You have to modify your code with the below if you want to make it worked perfectly:
self.resultSearchController = UISearchController(searchResultsController: nil)
self.resultSearchController.searchResultsUpdater = self
self.resultSearchController.searchBar.delegate = self
self.definesPresentationContext = true
self.resultSearchController.dimsBackgroundDuringPresentation = false
self.resultSearchController.hidesNavigationBarDuringPresentation = true
if #available(iOS 11.0, *) {
self.navigationItem.searchController = self.resultSearchController
} else {
self.tableView.tableHeaderView = self.resultSearchController.searchBar
}