Make UISearchController search bar automatically active
Asked Answered
R

4

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.

Rooke answered 7/7, 2015 at 16:14 Comment(6)
is searchController code is in viewDidLoadEvonneevonymus
Just to make sure if with your current code when you tap the search bar everything works fine ...right? And where did you put '[self.searchController.searchBar becomeFirstResponder]' in viewDidLoad?Rhizo
Yes everything works fine. I first tried in viewDidLoad then in viewDidAppear with both the same result, nothing.Rooke
So you already put '[self.searchController.searchBar becomeFirstResponder]' after initialising the search bar, correct?Rhizo
yes exactly, I've already done thatRooke
This issues have had the solution at link: https://mcmap.net/q/328795/-cannot-set-searchbar-as-firstresponderChafin
R
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;
}
Rhizo answered 7/7, 2015 at 17:16 Comment(6)
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.Rooke
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.Rhizo
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?Rooke
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.Rhizo
It's not work on iOS 9. Here're my solution: https://mcmap.net/q/328795/-cannot-set-searchbar-as-firstresponderChafin
it seems working when I added a 1 second delay when calling becomeFirstResponder.Mercie
A
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];
}
Apodosis answered 1/10, 2015 at 18:56 Comment(4)
please dont add plain code as answer. Explain how your answer solves the OP issue.Nightwear
Updated with the explanation.Apodosis
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.Goiter
I need to add a delay inside didPresentSearchController to get it works in iOS 12 simulator. I added 300ms delay which I think reasonable.Mercie
G
4

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()
        }
    }
}
Guttle answered 18/7, 2022 at 11:0 Comment(1)
Thank you. The final method worked for me - calling becomeFirstResponder() in main queue was what finally got it to work.Onassis
D
1

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

searchController.definesPresentationContext = YES;

Dilatometer answered 22/11, 2015 at 22:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.