I have a searchBar I\'m setting in a tableviewcontroller. i\'ve referenced this similar question UISearchBar cannot become first responder after UITableView did re-appear bu
I battled with this for a while but got it working by:
searchController
in viewDidLoad()
active = true
in viewDidAppear()
didPresentSearchController()
in the UISearchControllerDelegate
extension.searchBar.becomeFirstResponder()
in didPresentSearchController()
Here's the full example, it uses Google Maps Autocomplete.
class myViewController: UIViewController {
// MARK: Variables
var resultsViewController: GMSAutocompleteResultsViewController?
var searchController: UISearchController?
var resultView: UITextView?
// MARK: Outlets
@IBOutlet var myView: UIView!
// MARK: View Methods
override func viewDidLoad() {
super.viewDidLoad()
resultsViewController = GMSAutocompleteResultsViewController()
resultsViewController?.delegate = self
searchController = UISearchController(searchResultsController: resultsViewController)
searchController?.delegate = self
searchController?.searchResultsUpdater = resultsViewController
searchController?.searchBar.prompt = "Search for a Place"
searchController?.searchBar.placeholder = "place name"
searchController?.searchBar.text = ""
searchController?.searchBar.sizeToFit()
searchController?.searchBar.returnKeyType = .Next
searchController?.searchBar.setShowsCancelButton(true, animated: false)
myView.addSubview((searchController?.searchBar)!)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
searchController?.active = true
}
// MARK: GMSAutocompleteResultsViewControllerDelegate Extension
extension myViewController: GMSAutocompleteResultsViewControllerDelegate {
func resultsController(resultsController: GMSAutocompleteResultsViewController,
didAutocompleteWithPlace place: GMSPlace) {
searchController?.active = false
// Do something with the selected place.
print("Place name: ", place.name)
print("Place address: ", place.formattedAddress)
print("Place attributions: ", place.attributions)
}
func resultsController(resultsController: GMSAutocompleteResultsViewController,
didFailAutocompleteWithError error: NSError){
// TODO: handle the error.
print("Error: ", error.description)
}
// Turn the network activity indicator on and off again.
func didRequestAutocompletePredictionsForResultsController(resultsController: GMSAutocompleteResultsViewController) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
}
func didUpdateAutocompletePredictionsForResultsController(resultsController: GMSAutocompleteResultsViewController) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
}
}
extension myViewController: UISearchControllerDelegate {
func didPresentSearchController(searchController: UISearchController) {
self.searchController?.searchBar.becomeFirstResponder()
}
}
}
The solution with
- (void)didPresentSearchController:(UISearchController *)searchController
did not work, since this delegate method is called only when the user taps on the search bar...
However, this solution did work:
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self performSelector:@selector(showKeyboard) withObject:nil afterDelay:0.1];
}
- (void) showKeyboard
{
[self.searchController.searchBar becomeFirstResponder];
}
Swift 3
delay(0.1) { self.searchController.searchBar.becomeFirstResponder() }
func delay(_ delay: Double, closure: @escaping ()->()) {
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
To me, there’s a quite big lag when using viewDidAppear
. It can be better to use becomeFirstResponder
asynchronously in viewDidLoad
(tested with iOS 10, Swift 3):
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.async {
searchController.searchBar.becomeFirstResponder()
}
}