10

I've implemented a UISearchController with its search bar in a navigatiom bar and I would like to make the search bar active when the view is loaded. When I say active, I mean that the keyboard appears and the user can type his/her search without tap the search bar.

I initialised the UISearchController with the following code:

- (void)viewDidLoad
{
    self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
    [self.searchController setSearchResultsUpdater:self];
    [self.searchController setDimsBackgroundDuringPresentation:NO];
    [self.searchController setHidesNavigationBarDuringPresentation:NO];
    [self.navigationItem setTitleView:self.searchController.searchBar];

    [self setDefinesPresentationContext:YES];

    [self.searchController.searchBar setDelegate:self];
    [self.searchController.searchBar setShowsCancelButton:YES];
    [self.searchController.searchBar setPlaceholder:@"City or Airfield"];

    [self.searchController.searchBar sizeToFit];
}

I've tried to make my search controller active, call [self.searchController.searchBar becomeFirstResponder] and directly call searchBarSearchButtonClicked but nothing works.

Nonouf
  • 378
  • 2
  • 5
  • 19

4 Answers4

14

Try calling

[self.searchController setActive:YES]

before

[self.searchController.searchBar becomeFirstResponder]

If the above is not working, try something like this:

- (void)viewDidLoad {
    [super viewDidLoad];
    ...
    [self initializeSearchController];
    ....
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self.searchController setActive:YES];
    [self.searchController.searchBar becomeFirstResponder];
}

- (void)initializeSearchController {
    self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
    self.searchController.searchResultsUpdater = self;
    self.searchController.dimsBackgroundDuringPresentation = NO;
    self.searchController.delegate = self;
    self.searchController.searchBar.delegate = self;
    [self.searchController.searchBar sizeToFit];

    [self.tableView setTableHeaderView:self.searchController.searchBar];
    self.definesPresentationContext = YES;
}
SanitLee
  • 1,253
  • 1
  • 12
  • 29
  • 1
    I still have the same result. What I don't understand is that depsite the fact that I set active to YES, when I print `self.searchController.active` is still set to NO. – Nonouf Jul 07 '15 at 17:25
  • Actually to me, your code looks fine but you may have missed setting Active to search controller. I have updated my answer with splitting up into parts. Hopefully it may help ...just try it out. – SanitLee Jul 07 '15 at 17:36
  • Still the same result. I realised that I forgot to mention that I'm using a modal segue, do you think it could be a problem? – Nonouf Jul 08 '15 at 08:43
  • Hard to say because I don't see the relevant code to that. I'm now rather thinking about what you mentioned earlier that the search controller has never been active despite active setting. So if possible, you may try another approach by adding a subview with search bar and place it in navigation bar instead. – SanitLee Jul 08 '15 at 12:21
  • It's not work on iOS 9. Here're my solution: http://stackoverflow.com/a/37848770/3299612 – Tan Vu Jun 16 '16 at 02:11
  • it seems working when I added a 1 second delay when calling `becomeFirstResponder`. – John Pang Sep 22 '18 at 21:13
8

To activate the search bar:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self.searchController setActive:YES];
}

"becomeFistResponder" can be called to make the keyboard appear only when UISearchController is loaded .

- (void)didPresentSearchController:(UISearchController *)searchController
{
    [searchController.searchBar becomeFirstResponder];
}
dreamer.psp
  • 615
  • 7
  • 12
  • please dont add plain code as answer. Explain how your answer solves the OP issue. – Teja Nandamuri Oct 02 '15 at 18:02
  • Updated with the explanation. – dreamer.psp Oct 02 '15 at 18:42
  • For some reason, setting `[searchController setActive:YES];` in `viewDidLoad` does not work. This is due to something having to do with `searchController.searchBar` not being fully initialized in some way. There is also the possibility of a view related problem with `searchController.searchBar`. This solution also worked for me. – BenJammin Jan 09 '18 at 20:41
  • 2
    I need to add a delay inside `didPresentSearchController` to get it works in iOS 12 simulator. I added 300ms delay which I think reasonable. – John Pang Sep 22 '18 at 21:18
3

For those looking for a solution in 2022

I have tried the solution provided here with no luck.

So, here are the three approaches in swift that each seems to work.

  • Using delegate, make Searchcontroller active in the main queue.
class ViewController: UIViewController {

    private lazy var searchController = UISearchController()

    override func viewDidLoad() {
        super.viewDidLoad()
        searchController.delegate = self
        navigationItem.searchController = searchController
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // If this is not called in main queue, the searchbar is not being active
        DispatchQueue.main.async {
            self.searchController.isActive = true
        }
    }
}

extension ViewController: UISearchControllerDelegate {
    
    func didPresentSearchController(_ searchController: UISearchController) {
        DispatchQueue.main.async {
            searchController.searchBar.becomeFirstResponder()
        }
    }
}
  • Making the searchbar firstResponder after some delay.
class ViewController: UIViewController {

    private lazy var searchController = UISearchController()

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.searchController = searchController
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        delay(0.1) { self.searchController.searchBar.becomeFirstResponder() }
    }
    
    func delay(_ delay: Double, closure: @escaping ()-> Void) {
        let when = DispatchTime.now() + delay
        DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
    }
}
  • Or just making the searchbar firstResponder in main queue.
class ViewController: UIViewController {

    private lazy var searchController = UISearchController()

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.searchController = searchController
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        DispatchQueue.main.async {  // must call from main thread
            self.searchController.searchBar.becomeFirstResponder()
        }
    }
}
tanmoy
  • 1,276
  • 1
  • 10
  • 28
1

Besides doing what the other users suggested, I also did the following, and it worked:

searchController.definesPresentationContext = YES;

Natan R.
  • 5,141
  • 1
  • 31
  • 48