I have set up a UISearchController as a header for my tableview with the following code:
let mySearchController = UISearchController(searchResultsController: nil)
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
let keywords = searchBar.text
let finalKeywords = keywords?.replacingOccurrences(of: " ", with: "+")
searchUrl = "https://api.spotify.com/v1/search?q=\(finalKeywords!)&type=track&limit=20"
print(searchUrl)
callAlamo(url: searchUrl)
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(postCell.self, forCellReuseIdentifier: cellId)
tableView.separatorColor = .red
mySearchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
mySearchController.delegate = self as? UISearchControllerDelegate
tableView.tableHeaderView = mySearchController.searchBar
}
I adde a breakpoint at the searchBarButtonClicked function and at the print(searchUrl) inside of the function, but it never went to the breakpoints. Why is the searchBarSearchButtonClicked function not executing when I click on the search bar?
You are setting the wrong delegate. A UISearchBarController as a delegate property, but the method you are implementing is a UISearchBarDelegate method, so you need to set your object as the delegate for the search bar contained within the `UISearchBarController:
mySearchController.searchBar.delegate = self
Related
I would like to add a button to the left of the search bar. However, I don't want the the scope titles to shift over as well, leaving me with a gap somewhere. I believe my options to be:
remove scope bar, use UISegmentedControl below, and add a button in
modify the UISearchBarClass with a button
?? container view as header, includes button and search controller ??
Here is my code, refactored to use a UIViewController for easy modification. Note that I am using the SnapKit libary for constraints (table cell logic removed). How can I accomplish this?
class TeamSearchController: UIViewController {
let tableView = UITableView()
var searchBar = UISearchBar()
override func viewDidLoad() {
super.viewDidLoad()
initUI()
}
func initUI() {
self.view.addSubview(tableView)
initSearchController()
initTableView()
}
func initSearchController() {
// searchController.dimsBackgroundDuringPresentation = false
searchBar.placeholder = "Search for a team here..."
searchBar.delegate = nil
searchBar.sizeToFit()
searchBar.showsScopeBar = true
searchBar.scopeButtonTitles = ["Cross Country", "Track"]
// searchController.definesPresentationContext = true
}
func initTableView() {
tableView.dataSource = nil
tableView.delegate = nil
tableView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
tableView.tableHeaderView = searchBar
tableView.estimatedRowHeight = 40
tableView.rowHeight = UITableView.automaticDimension
}
}
Current Status:
i want to disable right cancel button when a tap at search Bar.
Because of using Google Place search i put i should use searchController?.searchBar
I try to disable cancel button at
func presentSearchController(_ searchController: UISearchController) {
searchController.searchBar.showsCancelButton = false
}
but when i tap a searchBar i see how cancel button appear and disappear, thats looks ugly
Please give me advice!
override func viewDidLoad() {
super.viewDidLoad()
resultsViewController = GMSAutocompleteResultsViewController()
resultsViewController?.delegate = self
searchController = UISearchController(searchResultsController: resultsViewController)
searchController?.searchResultsUpdater = resultsViewController
searchController?.searchBar.sizeToFit()
navigationItem.titleView = searchController?.searchBar
searchController?.searchBar.placeholder = searchBarPlaceholderText
searchController?.searchBar.tintColor = #colorLiteral(red: 0.1019607843, green: 0.5490196078, blue: 1, alpha: 1)
searchController?.searchBar.delegate = self
searchController?.delegate = self
searchController?.searchBar.searchBarStyle = .prominent
definesPresentationContext = true
mapView.delegate = self
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
checklocationAuthorizationStatus()
locationManager.requestWhenInUseAuthorization()
locationManager.requestLocation()
locationManager.startUpdatingLocation()
}
func presentSearchController(_ searchController: UISearchController) {
searchController.searchBar.showsCancelButton = false
}
You can create a custom class and subclass UISearchBar and UISearchViewController.
For example:-
class CustomizedSearchBar: UISearchBar {
override func layoutSubviews() {
super.layoutSubviews()
setShowsCancelButton(false, animated: false)
}
}
Now Create Object of the CustomizedSearchBar and use it within other viewController.
Or you can create a customized searchViewController as follows:
class CustomizedSearchController: UISearchController, UISearchBarDelegate {
lazy var _searchBar: CustomSearchBar = {
[unowned self] in
let result = CustomSearchBar(frame: CGRectZero)
result.delegate = self
return result
}()
override var searchBar: UISearchBar {
get {
return _searchBar
}
}
}
Please follow this link for more detail information.
I have implemented searchBar using UISearchController using following code -
var searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search here..."
definesPresentationContext = true
searchController.searchBar.delegate = self
searchController.searchBar.sizeToFit()
if #available(iOS 11.0, *) {
self.navigationItem.searchController = searchController
} else {
// Fallback on earlier versions
navigationItem.titleView = searchController.searchBar
navigationItem.titleView?.layoutSubviews()
}
Now I have two issues-
SearchBar comes below the navigationBar(See the image attached), how do I get the searchBar on top of NavigationBar that used to come when we implement searchBar with UISearch bar.
The cancel button is not coming on the right side of search bar.
I don't think you can do this natively. But you can activate the search bar when you open the menu (dont forget to set searchController.hidesNavigationBarDuringPresentation to true):
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
searchController.isActive = true
}
But it will hide the UINavigationBar so this is not what you really want. So, maybe better, you can create a custom navigation bar and hide the native one. Here is a quick example:
1 - Create a swift a xib file NavigationBarView with an horizontal UIStackView, a back UIButton with a fixed width and a UISearchBar:
class NavigationBarView: UIView {
var backAction: (()->Void)?
#IBOutlet weak var searchBarView: UISearchBar!
override func awakeFromNib() {
super.awakeFromNib()
// Customize your search bar
self.searchBarView.showsCancelButton = true
}
#IBAction func backButtonPressed(_ sender: Any) {
self.backAction?()
}
}
2 - Instead of using a UITableViewController, create a UIViewController with a vertical UIStackView which contains a view with a fixed height of 64 and a UITableView:
class TableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var containerView: UIView!
let navigationBarView: NavigationBarView = NavigationBarView.viewFromNib() // Custom helper to instantiate a view, see below
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.isHidden = true // hide the native UINavigationBar
self.navigationBarView.backAction = {
self.navigationController?.popViewController(animated: true)
}
self.navigationBarView.searchBarView.delegate = self
self.navigationBarView.add(in: self.containerView) // Custom helper to put a view in a container view, see below
// Other stuff
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
Here is my helpers:
extension UIView {
static public func viewFromNib <GenericView: UIView> () -> GenericView {
let className = String(describing: self)
guard let instance = UINib(nibName: className, bundle: nil)
.instantiate(withOwner: nil, options: nil).first as? GenericView else {
// If this happens, it means the xcodeproj is broken
fatalError("Ho no its broken!")
}
return instance
}
func add(in superView: UIView) {
self.translatesAutoresizingMaskIntoConstraints = false
superView.addSubview(self)
self.topAnchor.constraint(equalTo: superView.topAnchor).isActive = true
self.bottomAnchor.constraint(equalTo: superView.bottomAnchor).isActive = true
self.leftAnchor.constraint(equalTo: superView.leftAnchor).isActive = true
self.rightAnchor.constraint(equalTo: superView.rightAnchor).isActive = true
}
}
Yo can try below code and please let me know if you are facing any issue.
if self.searchController != nil {
self.searchController.isActive = false
}
isSearching = true
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 = false
self.navigationItem.titleView = searchController.searchBar
self.definesPresentationContext = false
self.searchController.searchBar.returnKeyType = .done
There is a property for this
searchController.hidesNavigationBarDuringPresentation = true
There is a gap, so it might be a white text Canel button. ou can know it for sure in Debugger Navigator (Cmd+7) -> View UI Hierarcy. White button text might be caused by custom navigation bar style
I have set up a search bar using the embed nav bar. The func searchBarSearchButtonClicked is not being detected. I'd like to make it so that when the user taps on the search bar, another function will be called. I've taken out some extraneous code not relevant to this question. What could be the issue?
class FirstViewController: UIViewController, UISearchBarDelegate {
var resultSearchController: UISearchController? = nil
override func viewDidLoad() {
super.viewDidLoad()
// set up the search results table
let locationSearchTable = storyboard!.instantiateViewController(withIdentifier: "LocationSearchTable") as! LocationSearchTable
resultSearchController = UISearchController(searchResultsController: locationSearchTable)
resultSearchController?.searchResultsUpdater = locationSearchTable
let searchBar = resultSearchController!.searchBar
searchBar.sizeToFit()
searchBar.placeholder = "Where would you like to go"
navigationItem.titleView = resultSearchController?.searchBar
searchBar.delegate = self
resultSearchController?.hidesNavigationBarDuringPresentation = false
resultSearchController?.dimsBackgroundDuringPresentation = true
definesPresentationContext = true
}
func searchBarSearchButtonClicked(_: UISearchBar) {
// closeMapType()
// self.mapType.transform = .identity
print("it worked")
}
}
Below function will call when the user taps on the search bar :
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
return true
}
This will call when we click on the "Search" button in the keyboard
func searchBarSearchButtonClicked(_: UISearchBar)
I created a UISearchController in a table view controller. I segue to this table view controller using a push segue from another view controller. I want the keyboard to show up with the cursor in the search bar as soon as the table view controller is pushed.
I made the search controller active in the viewDidLoad method using
self.mySearchController.active = true
It does make the search controller active but this does not bring up the keyboard nor is the cursor placed in the search bar. I also tried
self.mySearchController.searchBar.becomeFirstResponder()
This line does not seem to have any effect.
How do I bring up the keyboard automatically/programmatically? Below is a more detailed version of my code
class PickAddressViewController: UITableViewController, UISearchResultsUpdating {
var searchText = ""
var mySearchController = UISearchController()
override func viewDidLoad() {
super.viewDidLoad()
self.mySearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
controller.searchBar.text = self.searchText
self.tableView.tableHeaderView = controller.searchBar
return controller
})()
self.mySearchController.active = true
self.mySearchController.searchBar.becomeFirstResponder()
}
BecomeFirstResponder is the way to go, but you should do it not in viewDidLoad. Look at following discussion for details - Cannot set searchBar as firstResponder
I also tried the suggestions listed in the link mentioned by Nikita Leonov. I needed to add make the class a UISearchControllerDelegate & UISearchBarDelegate and then it worked. I don't u
class PickAddressViewController: UITableViewController, UISearchControllerDelegate, UISearchBarDelegate, UISearchResultsUpdating {
override func viewDidLoad() {
super.viewDidLoad()
self.mySearchController = ({
controller.searchBar.delegate = self
})()
self.mySearchController.active = true
self.mySearchController.delegate = self
}
func didPresentSearchController(searchController: UISearchController) {
self.mySearchController.searchBar.becomeFirstResponder()
}
…
}
Swift 5
in viewDidLoad:
searchViewController.delegate = self
in viewDidAppear:
searchViewController.isActive = true
This activates the SearchController
Define a delegate method:
extension MyViewController: UISearchControllerDelegate {
func didPresentSearchController(_ searchController: UISearchController) {
DispatchQueue.main.async {
searchController.searchBar.becomeFirstResponder()
}
}
}
Swift 3 solution in my case:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.titleView = mySearchController.searchBar
mySearchController.searchResultsUpdater = self
mySearchController.delegate = self
}
override func viewDidAppear(_ animated: Bool) {
DispatchQueue.main.async {
self.mySearchController.isActive = true
}
}
func presentSearchController(_ searchController: UISearchController) {
mySearchController.searchBar.becomeFirstResponder()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
self.navigationItem.titleView = searchController!.searchBar
dispatch_async(dispatch_get_main_queue(), {
self.searchController?.active = true
self.searchController!.searchBar.becomeFirstResponder()
})
}
and this code
func presentSearchController(searchController: UISearchController) {
searchController.searchBar.becomeFirstResponder()
}
make sure you give
searchController?.delegate = self in viewDidLoad(). Tested on iOS 9.* device
Besides doing what the other users suggested, I also did the following, and it worked:
searchController.definesPresentationContext = true