Cancel out of UISearchBar when user taps on view

13,181

Solution 1

An alternative idea I got from iphonedevbook, sample code project 04, was to use one big transparent button that lies behind all other controls which does nothing but resign all first responders if tapped. I.e. if the user taps anywhere where there isn't a more important control - which is the intuitive behavior - the search bar and keyboard disappear.

Solution 2

Add a tap gesture in the parent view (of the UISearchbar)

[self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:searchBar action:@selector(resignFirstResponder)]];

Solution 3

I accomplished this by using a UITapGestureRecognizer:

UIGestureRecognizer* cancelGesture;

- (void) backgroundTouched:(id)sender {
    [self.view endEditing:YES];
}

#pragma mark - UISearchBarDelegate

-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
    cancelGesture = [UITapGestureRecognizer new];
    [cancelGesture addTarget:self action:@selector(backgroundTouched:)];
    [self.view addGestureRecognizer:cancelGesture];
}

-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
    if (cancelGesture) {
        [self.view removeGestureRecognizer:cancelGesture];
        [cancelGesture release];
        cancelGesture = nil;
    }
}

The code is a bare, but you can see the intent. When the SearchBar starts editing, you attach a tap gesture recognizer to the view controller's view, and remove it when it stops editing.

There are a couple caveats that you can work around: doing this will make it so if you click anything besides the keyboard or the search bar's text field, the recognizer traps the click -- so if you use the clear, cancel, scope or results button they won't respond correctly.

In my particular scenario, I had a UITableView that was covering the exposed area of the view so I attached the gesture recognizer to it instead of the view controllers main view, isolating the area to which the gesture would respond.

Solution 4

I ended up using a hybrid of Hauke's and Beau Scott's approach. There were two problems I ran into using their solutions:

1) If there's anything else on the screen, tapping it won't result in resignFirstResponder being called. For example, if the user taps a button rather than the space around the button, the button will eat the event. Beau Scott's solution addresses this issue, however.

2) Tapping the search bar itself will result in resignFirstResponder getting called. Clearly you don't want the keyboard to disappear when you tap UISearchBar. A small change described below addresses this.

I ended up setting up my view as follows. The parent view has two children - the UISearchBar and a subview which holds the rest of my UI elements. The subview takes up the entire screen below the UISearchBar. Then I used Beau Scott's exact code to add and remove the gesture recognizer, but instead of adding it to self.view I added it to the subview:

IBOutlet UIView *gestureRecognizer;

...

-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
    cancelGesture = [UITapGestureRecognizer new];
    [cancelGesture addTarget:self action:@selector(backgroundTouch:)];
    [gestureRecognizer addGestureRecognizer:cancelGesture];
}

-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
    if (cancelGesture) {
        [gestureRecognizer removeGestureRecognizer:cancelGesture];
        [cancelGesture release];
        cancelGesture = nil;
    }
}
Share:
13,181
Bryan C
Author by

Bryan C

Updated on June 08, 2022

Comments

  • Bryan C
    Bryan C almost 2 years

    Does anyone know how to cancel (resign First Responder) out of a UISearchBar when you tap below the search text box and above the keyboard? Can anyone help post some code to handle this?

    Thanks