Jasarien
Jasarien

Reputation: 58478

Can I hook into UISearchBar's Clear Button?

I've got a UISearchBar in my interface and I want to customise the behaviour of the the small clear button that appears in the search bar after some text has been entered (it's a small grey circle with a cross in it, appears on the right side of the search field).

Basically, I want it to not only clear the text of the search bar (which is the default implementation) but to also clear some other stuff from my interface, but calling one of my own methods.

I can't find anything in the docs for the UISearchBar class or the UISearchBarDelegate protocol - it doesn't look like you can directly get access to this behaviour.

The one thing I did note was that the docs explained that the delegate method:

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText;

is called after the clear button is tapped.

I initially wrote some code in that method that checked the search bar's text property, and if it was empty, then it had been cleared and to do all my other stuff.

Two problems which this though:

Firstly, for some reason I cannot fathom, even though I tell the search bar to resignFirstResponder at the end of my method, something, somewhere is setting it back to becomeFirstResponder. Really annoying...

Secondly, if the user doesn't use the clear button, and simply deletes the text in the bar using the delete button on the keyboard, this method is fired off and their search results go away. Not good.

Any advice or pointers in the right direction would be great!

Thanks!

Upvotes: 37

Views: 52400

Answers (9)

ergunkocak
ergunkocak

Reputation: 3380

Swift version handling close keyboard on clear button click :

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
    if searchText.characters.count == 0 {
        performSelector("hideKeyboardWithSearchBar:", withObject:searchBar, afterDelay:0)
    }
}

func hideKeyboardWithSearchBar(bar:UISearchBar) {
    bar.resignFirstResponder()
}

Upvotes: 7

user243969
user243969

Reputation:

Wasn't able to find a solution here that didn't use a private API or wasn't upgrade proof incase Apple changes the view structure of the UISearchBar. Here is what I wrote that works:

- (void)viewDidLoad {
    [super viewDidLoad];

    UITextField* textfield = [self findTextFieldInside:self.searchBar];
    [textfield setDelegate:self];
}

- (UITextField*)findTextFieldInside:(id)mainView {
    for (id view in [mainView subviews]) {
        if ([view isKindOfClass:[UITextField class]]) {
            return view;
        }

        id subview = [self findTextFieldInside:view];
        if (subview != nil) {
            return subview;
        }
    }

    return nil;
}

Then implement the UITextFieldDelegate protocol into your class and overwrite the textFieldShouldClear: method.

- (BOOL)textFieldShouldClear:(UITextField*)textField {
    // Put your code in here.
    return YES;
}

Edit: Setting the delegate on the textfield of a search bar in iOS8 will produce a crash. However it looks like the searchBar:textDidChange: method will get called on iOS8 on clear.

Upvotes: 0

Waqas Haider Sheikh
Waqas Haider Sheikh

Reputation: 870

Found the better solution for this problem :)

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
    if ([searchText length] == 0) {
        [self performSelector:@selector(hideKeyboardWithSearchBar:) withObject:searchBar afterDelay:0];
    }
}

- (void)hideKeyboardWithSearchBar:(UISearchBar *)searchBar{   
    [searchBar resignFirstResponder];   
}

Upvotes: 18

Denis Redis
Denis Redis

Reputation: 31

You could try this:

- (void)viewDidLoad
{
    [super viewDidLoad];
    for (UIView *view in searchBar.subviews){
        for (UITextField *tf in view.subviews) {
            if ([tf isKindOfClass: [UITextField class]]) {
                tf.delegate = self;
                break;
            }
        }
    }
}

- (BOOL)textFieldShouldClear:(UITextField *)textField {
     // your code
    return YES;
}

Upvotes: 2

Peter Lapisu
Peter Lapisu

Reputation: 21005

Best solution from my experience is just to put a UIButton (with clear background and no text) above the system clear button and than connect an IBAction

- (IBAction)searchCancelButtonPressed:(id)sender {

    [self.searchBar resignFirstResponder];
    self.searchBar.text = @"";

    // some of my stuff
    self.model.fastSearchText = nil;
    [self.model fetchData];
    [self reloadTableViewAnimated:NO];

}

Upvotes: 0

SmileBot
SmileBot

Reputation: 19672

Since this comes up first, and far as I can see the question wasn't really adequately addressed, I thought I'd post my solution.

1) You need to get a reference to the textField inside the searchBar 2) You need to catch that textField's clear when it fires.

This is pretty simple. Here's one way.

a) Make sure you make your class a , since you will be using the delegate method of the textField inside the searchBar. b) Also, connect your searchBar to an Outlet in your class. I just called mine searchBar. c) from viewDidLoad you want to get ahold of the textField inside the searchBar. I did it like this.

UITextField *textField = [self.searchBar valueForKey:@"_searchField"];
if (textField) {
    textField.delegate = self;
    textField.tag = 1000;
}

Notice, I assigned a tag to that textField so that I can grab it again, and I made it a textField delegate. You could have created a property and assigned this textField to that property to grab it later, but I used a tag.

From here you just need to call the delegate method:

-(BOOL)textFieldShouldClear:(UITextField *)textField {
if (textField.tag == 1000) {
    // do something
    return YES;
}
return NO;

}

That's it. Since you are referring to a private valueForKey I can't guarantee that it will not get you into trouble.

Upvotes: 1

boliva
boliva

Reputation: 5634

The answer which was accepted is incorrect. This can be done, I just figured it out and posted it in another question:

UISearchbar clearButton forces the keyboard to appear

Best

Upvotes: 12

Rengers
Rengers

Reputation: 15238

I've got this code in my app. Difference is that I don't support 'live search', but instead start searching when the user touches the search button on the keyboard:

- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
    if ([searchBar.text isEqualToString:@""]) {
        //Clear stuff here
    }
}

Upvotes: 7

Andrew
Andrew

Reputation: 8563

I would suggest using the rightView and rightViewMode methods of UITextField to create your own clear button that uses the same image. I'm assuming of course that UISearchBar will let you access the UITextField within it. I think it will.
Be aware of this from the iPhone OS Reference Library:

If an overlay view overlaps the clear button, however, the clear button always takes precedence in receiving events. By default, the right overlay view does overlap the clear button.

So you'll probably also need to disable the original clear button.

Upvotes: 1

Related Questions