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 but am still unable to set it as first responder. In .h file:
@property (strong, nonatomic) UISearchController *searchController;
@property (strong, nonatomic) IBOutlet UISearchBar *searchBar;
In view didload:
self.searchController = [[UISearchController alloc]initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.hidesNavigationBarDuringPresentation = NO;
self.searchController.searchBar.frame = CGRectMake(self.searchController.searchBar.frame.origin.x, self.searchController.searchBar.frame.origin.y, self.searchController.searchBar.frame.size.width, 44.0);
self.tableView.tableHeaderView = self.searchController.searchBar;
And in viewDidAppear:
-(void)viewDidAppear:(BOOL)animated {
[self.searchController setActive:YES];
[self.searchController.searchBar becomeFirstResponder];
[super viewDidAppear:animated];
}
When I segue to the view the searchBar animates, but no keyboard appears.
Swift 5
solution:The answer is to call becomeFirstResponder in viewDidAppear.
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:
Swift 3
Easy Swift3 variant:
It works ;-)
Alternative Approach
(Source of
self.definesPresentationContext
solution - See SO answer)One thing to keep in mind is the context of how the SearchBar is being presented. Embedded in a toolbar, navigation bar, another UIView, as an input or input accessory view. All of which, I've found to have some impact on the timing and internal animation of the search bar as it is being presented or dismissed.
I've attempted all of the solutions presented and none of these worked until I reconsidered how I was trying to use the searchBar. In my case, I was pushing a controller (B) with a search controller from a controller (A) that already had an initial searchcontroller on it. I programmatically embedded each of the search controllers within the titleView of my navigation item when doing a pull refresh.
The answers suggesting adding
searchbar.becomeFirstResponder()
into the life cycle didn't make sense for my use-case since the view was fully loaded by the time I wanted to insert and display my search bar into the navigationItem. The logic also seemed confusing since the view controller lifecycle methods should already be operating on the main thread. Adding a delay to the presentation also seemed to be an interference with the internal operations of the display and animation used by the system.I found that calling my function to toggle the insertion worked when I pushed the view controller from controllerA but the keyboard would not display properly when pushed from controllerB. The difference between these two situations was that controllerA was a static tableview controller and controllerB had a tableview controller that I had made searchable by adding its own search controller.
Using a number of breakpoints and examining the status of the searchController and the searchbar at different points I was able to determine that the
searchController.canBecomeFirstResponder
was returningfalse
. I also found that I needed to set theSearchResultsUpdater
toself
and the delegates on both the searchController and the searchBar.I finally noted that setting
self.definesPresentationContext = true
on controllerA was not allowing the keyboard to be displayed when I pushed controllerB onto the navigation stack. My solution was to move theself.definesPresentationContext = true
toviewDidAppear
on controllerA and in theprepare(for:sender:)
method of controllerA I change it toself.definesPresentationContext = false
when the destination is controllerB. This resolved the keyboard display issue in my case.A word on animation ~ I've found that when assigning things to the navigationItem or navigationBar, the system has some built in timing and default animations. I avoid adding custom animation, code in moveToParent methods, or delayed presentations because unexpected behavior occurs in many cases.
Why this solution works
Apple documentation on
definesPresentationContext
indicates the default behavior and notes some situations where this context adjusts the behavior the controller assigned to manage the keyboard appearance. In my case controllerA was assgined to manage the presentation rather than controllerB, so I just changed that behavior by adjusting this value:This is what it worked for me in Swift 4