I'm trying to find an alternative to displaysSearchBarInNavigationBar for iOs8, is there anything I can use (in swift)?
I tried self.navigationItem.titleView = resultSearchController.searchBar but it doesn't do anything.
I don't understand how to find the replacement for functions that are deprecated, on the apple documentation it just say deprecated with no alternative, if you have any tips it would be greatly appreciated.
You can put an UISearchBar in a UINavigationBar without using a UINavigationController without problem, but you have to do a minor change only, first you need to define an #IBOutlet to the UINavigationItem inside your UINavigationBar but its name need to be different from the navigationItem property defined in all the UIViewController class, see the following code:
class ViewController: UIViewController, UISearchControllerDelegate, UISearchResultsUpdating, UISearchBarDelegate {
var searchController : UISearchController!
#IBOutlet weak var navigationItemBar: UINavigationItem!
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.navigationItemBar.titleView = searchController.searchBar
self.definesPresentationContext = true
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
And then you can see something like this in your simulator:
I hope this help you.
Related
I am implementing a search feature in my app. The app consists of a view controller and a custom class that handles the search logic. This custom class is called SearchController.
My goal is to make the searchBar notify the view controller when the user is about to begin searching (exactly the same behaviour as the UISearchBarDelegate method searchBarShouldBeginEditing).
Normally, you would just declare searchBarShouldBeginEditing inside SearchController but I am trying to call this method from inside the viewController because I want something in my view to change when this event happens (and thus the viewController should be handling it, not the searchController).
SearchController class:
class SearchController: NSObject, UISearchBarDelegate {
let searchBar = UISearchBar()
var searchButton = UIBarButtonItem? = nil
/* Other irrelevant class properties */
func setup() {
searchBar.delegate = self
/* other setup */
}
}
ViewController class:
class ViewController: UIViewController {
private let searchController = SearchController()
override func viewDidLoad() {
super.viewDidLoad()
searchController.delegate = self
searchController.setup()
}
/* setup a tableview to display results... this part of the implementation works fine */
}
I omitted the majority of these two classes because the search feature already works. The only thing I am struggling with is finding a way to let viewController know when the user is about to begin typing into the search field.
I tried making viewController implement UISearchBarDelegate but I am already making SearchController implement UISearchBarDelegate so why can't I access the delegate methods inside viewController?
I hope I made myself clear, I can clarify this post further if necessary. I have been tearing my hair out trying to figure this out on my own.
Ok, a searchBar cannot have 2 delegates, so you're gonna have to find a way to work around that.
One way to go about this is this:
protocol SearchControllerDelegate: class{
func searchBarDidBeginEditing()
}
class SearchController: NSObject, UISearchBarDelegate {
weak var delegate: SearchControllerDelegate?
private let searchBar = UISearchBar()
func setup() {
searchBar.delegate = self
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
delegate?.searchBarDidBeginEditing()
}
}
class ViewController: UIViewController, SearchControllerDelegate{
var searchController = SearchController()
func setUP(){
self.searchController.delegate = self
}
func searchBarDidBeginEditing() {
/// perform some action here
}
}
You can use UISearchController as rmaddy suggested, implement UISearchResultsUpdating
ViewController class:
class ViewController: UIViewController, UISearchResultsUpdating {
private let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.delegate = self
....
}
// Called when the search bar's text or scope has changed or when the search bar becomes first responder.
func updateSearchResults(for searchController: UISearchController) {
//Do something...
}
}
Or if you really want to implement the search bar logic yourself, you can go with the closure:
SearchController class:
class SearchController: NSObject, UISearchBarDelegate {
let searchBar = UISearchBar()
var searchButton = UIBarButtonItem? = nil
var didBeginSearching: (() -> ())?
/* Other irrelevant class properties */
func setup() {
searchBar.delegate = self
/* other setup */
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
didBeginSearching?()
}
}
ViewController class:
class ViewController: UIViewController {
private let searchController = SearchController()
override func viewDidLoad() {
super.viewDidLoad()
searchController.setup()
searchController.didBeginSearching = { [weak self] in
//Do something...
}
}
}
I have set the delegate in the viewDidLoad() method and also checked the IB to see if the delegate shows up when using (control + drag) and it does infact show as being hooked up. I deleted it as well and added a new SearchBar entirely in IB and hooked it back up. Nothing seems to do the trick. Any suggestions?
override func viewDidLoad() {
self.searchBar.layer.zPosition = 1
self.searchBar.delegate = self
}
//this is never being called, breakpoint never hits
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
print("searchText \(searchText)")
}
//this is never being called, breakpoint never hits
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
print("search button clicked")
self.firebaseQuery()
}
Is your custom View Controller class set in Interface Builder? I.e. on the Identity Inspector tab, ensure your desired UIViewController subclass is set in the Custom Class section.
Also, try setting a breakpoint in viewDidLoad(). Run the app and if the breakpoint doesn't get hit when you expect, that helps narrow down the problem.
Is it possible you're setting the delegate incorrectly?
In Interface Builder, command-click the search bar, drag the delegate to the yellow ViewController button in the storyboard to set the delegate.
Remove self.searchBar.delegate = self from viewDidLoad()
I'm also not seeing if your viewController Class has properly conformed to UISearchBarDelegate I would add it in an extension to your controller and put all your code relating to it there.
class ViewController: UIViewController{...}
extension ViewController: UISearchBarDelegate {
// implement all searchBar related methods here:
func searchBarButtonClicked(_ searchBar: UISearchBar) {
//capture the string
if let input = searchBar.text {
// do something with string.
print(input)
}
}
I also had a problem with it not responding when I set it up using IB. I finally set it up using code instead of IB, and it worked. Try it this way:
class MySearchTableViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
self.searchController.searchBar.autocapitalizationType = UITextAutocapitalizationType.none
self.navigationItem.searchController = self.searchController
//if this is set to true, the search bar hides when you scroll.
self.navigationItem.hidesSearchBarWhenScrolling = false
//this is so I'm told of changes to what's typed
self.searchController.searchResultsUpdater = self
self.searchController.searchBar.delegate = self
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
//hopefully this gets called when you click Search button
}
func updateSearchResults(for searchController: UISearchController) {
//if you want to start searching on each keystroke, you implement this method. I'm going to wait until they click Search.
}
https://www.reddit.com/r/swift/comments/85o75h/bug_uisearchbar_delegate_methods_not_being_called/dvzcbb4/
Thanks to reddit user #applishish I got the issue
I did not put a underscore in front of the parameter -_-
Thanks all for your help!
class PlaceSelectorViewController: UIViewController, GMSAutocompleteResultsViewControllerDelegate, UISearchBarDelegate {
I have included searchbar delegate
searchController?.searchBar.delegate = self
and I have set the delegate.
But method
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
stopHighlight()
}
doesn't happen.
Delegate has set properly and stopHighlight() is a real function
Make delegate of searchbar in viewdidload method.
override func viewDidLoad() {
super.viewDidLoad()
searchBarCustom.delegate = self
}
or you can set it in storyboard as
-hence delegates will call as
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
print("searchBarCancelButtonClicked")
}
EDIT:
For UISearchController
var searchController: UISearchController!
func configureSearchController() {
// Initialize and perform a minimum configuration to the search controller.
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search here..."
searchController.searchBar.delegate = self
searchController.searchBar.sizeToFit()
// Place the search bar view to the tableview headerview.
tblSearchResults.tableHeaderView = searchController.searchBar
}
In my case, it was a spelling error.
Make sure your #IBOutlet name is similar with your delegate name.
Example,
#IBOutlet weak var SearchBar: UISearchBar!
Set the delegate in viewDidLoad():
override func viewDidLoad() {
super.viewDidLoad()
SearchBar.delegate = self
I am using the UISearchController and the search function works except for two things. Perhaps they are related:
a) The keyboard does not show. So I cannot press the "Search" button
b) In my main TableView I access the prototype cell that has the style "Subtitle". When the search is going on, the cell that shows is "Basic" style. In both cases (TableViewController and SearchViewController) I use the same cell identifier.
Any ideas? Here some of the code:
class OverviewTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
let resultsController = SearchResultsController()
resultsController.birds = birds
searchController = UISearchController(searchResultsController: resultsController)
//searchController.dimsBackgroundDuringPresentation = true
let searchBar = searchController.searchBar
searchBar.scopeButtonTitles = ["One", "Two"]
searchBar.placeholder = "Search"
searchBar.sizeToFit()
tableView.tableHeaderView = searchBar
searchController.searchResultsUpdater = resultsController
and the second class:
class SearchResultsController: UITableViewController, UISearchResultsUpdating {
var items: [Item] = []
var filtered: [Item] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
// MARK: - UISearchResultsUpdating Conformance
func updateSearchResultsForSearchController(searchController: UISearchController) {
//searchController.hidesNavigationBarDuringPresentation = true
let searchString = searchController.searchBar.text
let buttonIndex = searchController.searchBar.selectedScopeButtonIndex
filtered.removeAll(keepCapacity: true)
if !searchString.isEmpty {
for item in items {
...
}
}
self.tableView.reloadData()
}
}
I had the same issue and basically if your parent class has a UISearchController as well as your child class and you're setting the
self.definesPresentationController = YES
in your parent class, your child class' search controller won't have the keyboard showing. Took me a while to figure out but this is what is happening.
The way to fix it is to set the self.definesPresentationController = NO when your parent class is about to push the child class and set self.definesPresentationController = YES in the viewWillAppear of your parent class...
Hope this helps someone out there too.
In my main TableView I access the prototype cell that has the style "Subtitle". When the search is going on, the cell that shows is "Basic" style
Make sure that cells in the SearchResultsController are also of "Subtitle" style.
Besides doing what the other users suggested, I also did the following, and it worked:
searchController.definesPresentationContext = true
I try to create a toolbar with a UIBarButtonItem with a customView (UISwitch). This is done by my function "createtoolbar()".
On viewDidLoad() the toolbar is created properly.
BUT: Creating the toolbar by pressing a Button, the UISwitch disappears approx. 0.1 seconds later.
Hope someone can help me! :)
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
createtoolbar()
}
#IBOutlet var bottomBar: UIToolbar!
let alarmSwitch = UISwitch()
func createtoolbar() {
alarmSwitch.on = true
let alarmSwitchBarButton = UIBarButtonItem(customView: alarmSwitch)
var toolbarbuttons = [alarmSwitchBarButton]
bottomBar.setItems(toolbarbuttons, animated: true)
}
#IBAction func createtoolbarButtonPressed(sender: AnyObject) {
createtoolbar()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
It's unclear what you're trying to do. You're creating the bar button item in code but adding a switch that's an IBOutlet? You can't do that -- if your switch actually is an IBOutlet, then it will already be the subview of some other view, and you can't use it in you bar button. If it's not an IBOutlet (which to shouldn't be), then you need to create the switch in code.