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 noticed this issue too. What seems to happen is the call to becomeFirstResponder
is done when the searchController is still 'loading'. If you comment out becomeFirstResponder
you notice that there is no difference. So we need a way to call becomeFirstResponder after the searchController is 'done' loading.
When I looked at various delegate methods I noticed there is a delegate method:
- (void)didPresentSearchController:(UISearchController *)searchController
This method is called right after the searchController has been presented. Then I make the call to becomeFirstResponder
:
- (void)didPresentSearchController:(UISearchController *)searchController
{
[searchController.searchBar becomeFirstResponder];
}
This fixes the problem. You will notice that when the searchController is loaded, the searchbar now has focus.
The answer is to call becomeFirstResponder in viewDidAppear.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
searchBar?.becomeFirstResponder()
}
Well, I found the solution that is actually perfectly working for me.
Don't call [self.searchController setActive:YES];
before calling [self.searchController.searchBar becomeFirstResponder];
What's better, don't call [self.searchController setActive:YES];
at all.
Call only [self.searchController.searchBar becomeFirstResponder];
and the keyboard just pops out as it should, without any delay.
It seems to be somewhat like a bug and a lot of people are confirming it. For example, check here: When assigning focus via becomeFirstResponder to UISearchController's UISearchBar, the keyboard does not appear
i fixed this as follows:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
searchController.isActive = true
}
func didPresentSearchController(_ searchController: UISearchController) {
DispatchQueue.main.async {
searchController.searchBar.searchTextField.becomeFirstResponder()
}
}
What happens is as soon as the view appears you set your searchControllers 'isActive' property to true. This fires the delegate method called didPresentSearchController. when that fires it means that searchcontroller is visible and thus can become first responder.
Based on @mislovr's solution, the 0.1
delay was not long enough. Here is my updated code to that answer.
func presentSearchController() {
searchController.isActive = true
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak searchController] timer in
guard let searchController = searchController else {
timer.invalidate()
return
}
if searchController.searchBar.canBecomeFirstResponder {
searchController.searchBar.becomeFirstResponder()
timer.invalidate()
}
}
}
Very similar to other answers, but I had to access the main queue in the ViewDidAppear
.
The SearchBarController
can't be acted upon until the View
appears and then can only be done so in the main queue for UI
:
searchController.active = true // doubtful whether this is needed
dispatch_async(dispatch_get_main_queue(), {
self.searchController.searchBar.becomeFirstResponder()
});