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
}
Related
Maybe this is impossible, but I always assumed you could just throw a UISearchController instance onto any old view controller's navigationItem and get a search bar. It seems to me like no matter what I try, I can't get it to work. It's making me think this behavior is hardcoded to only work when the view controller's view property is a subclass of UIScrollView.
I hope this is just a red herring. If I missed something obvious, please help! This is infuriating.
Here's what I did:
import UIKit.UIViewController
class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.hidesSearchBarWhenScrolling = false
navigationItem.searchController = {
let searchController = UISearchController()
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
searchController.obscuresBackgroundDuringPresentation = false
return searchController
}()
}
}
No search bar ever appears on screen. It just looks like a regular old navigation bar.
The UISearchController initializer should be let searchController = UISearchController(searchResultsController: nil) or replace nil with a seperate controller to display the search results.
If your viewController is in a UINavigationController stack then the above code should work (with the corrected initializer). Otherwise you will need to create a UINavigationBar and add it to the view. Then add the searchController.searchBar to the navigationItem.titleView
let navigationBar = UINavigationBar()
view.addSubview(navigationBar)
navigationBar.barTintColor = UIColor.gray
navigationBar.translatesAutoresizingMaskIntoConstraints = false
navigationBar.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
navigationBar.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
navigationBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
navigationBar.delegate = self
navigationBar.items = [navigationItem]
navigationItem.searchController = {
let searchController = UISearchController(searchResultsController: nil)
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
searchController.obscuresBackgroundDuringPresentation = false
return searchController
}()
navigationItem.titleView = navigationItem.searchController?.searchBar
override func viewDidLoad() {
let searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
self.tableView?.tableHeaderView = searchController.searchBar
}
This is default behavior when you add the search bar to tableview header.
I've implemented UISearchController and presenting it on UIViewController.
Navigation bar has search button and on clicking search, UISearchController will present from top of the screen.
Issue is, In iPhone X it looks fine but in all other devices it doesn't fit properly with spacing.
My implementation is like this :
let searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.delegate = self
searchController.searchBar.tintColor = UIColor.white
searchController.searchBar.sizeToFit()
searchController.searchBar.placeholder = SEARCH
searchController.searchBar.barTintColor = UIColor(hex: 0x2A3442)
searchController.searchBar.becomeFirstResponder()
// Search bar UI change
for subview in searchController.searchBar.subviews {
for innerSubview in subview.subviews {
if innerSubview is UITextField {
let textField = innerSubview as? UITextField
textField?.textColor = UIColor.white
textField?.borderStyle = .roundedRect
textField?.backgroundColor = UIColor(hex: 0x38465A)
}
}
}
present(searchController, animated: true)
If I embed the ViewController into a Navigation Bar, navigationItem.titleView.resultSearchController?.searchBar will put a search bar into the navigation bar. However, I've created a UISearchController and a UINavigationBar with code. This time, the navBar is showing up, but the searchBar isn't.
resultSearchController = UISearchController(searchResultsController: locationSearchTable)
resultSearchController?.searchResultsUpdater = locationSearchTable
let searchBar = resultSearchController!.searchBar
searchBar.sizeToFit()
searchBar.delegate = self
let navBar: UINavigationBar = UINavigationBar(frame: CGRect(x: 0, y:0, width: 375, height: 64))
self.view.addSubview(navBar)
//navBar.topItem = resultSearchController?.searchBar
self.navigationItem.titleView = resultSearchController?.searchBar
navBar.topItem = resultSearchController?.searchBar doesn't work because topItem is a String value and resultSearchController?.searchBar is a UIView type. How can I achieve the same effect?
Create a UINavigationItem instance and add it to the created navigation bar.
Add the search controller search bar to the UINavigationItem as titleView.
class SearchViewController: UIViewController, UISearchControllerDelegate, UISearchResultsUpdating, UISearchBarDelegate {
var searchController: UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
self.addNavigationbar()
}
func addNavigationbar() {
let navBar = UINavigationBar(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 60))
self.view.addSubview(navBar)
let navigationItem = UINavigationItem(title: "")
self.searchController = searchControllerWith(searchResultsController: nil)
navigationItem.titleView = self.searchController.searchBar
navBar.setItems([navigationItem], animated: false)
self.definesPresentationContext = true
}
func searchControllerWith(searchResultsController: UIViewController?) -> UISearchController {
let searchController = UISearchController(searchResultsController: searchResultsController)
searchController.delegate = self
searchController.searchResultsUpdater = self
searchController.searchBar.delegate = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = true
return searchController
}
class UIViewController: UIViewController, UISearchControllerDelegate, UISearchResultsUpdating, UISearchBarDelegate {
var searchController : UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
self.searchController = UISearchController(searchResultsController: nil)
self.searchController.searchResultsUpdater = self
self.searchController.delegate = self
self.searchController.searchBar.delegate = self
self.searchController.hidesNavigationBarDuringPresentation = false
self.searchController.dimsBackgroundDuringPresentation = true
self.navigationItem.titleView = searchController.searchBar
self.definesPresentationContext = true
}
func updateSearchResults(for searchController: UISearchController) {
}
}
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