21

I have a UIViewController with a UISearchBar. I have replaced the Search Button by a Done button.

However, when one taps on the searchbar, the Done button is initially disabled. This occurs until one enters any character.

What I want to do is to have this Done button always enabled, such that if i tap on it i can inmediately dismiss the keyboard.

Any help? it would be highly appreciated.

I have on my UIViewController

-(BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar  
{   
    return YES;  
}  

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

-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText  
{  
    if (searchBar.text.length == 0)  
    {  
        //[self fixOrientation];  
        [searchBar resignFirstResponder];  
    }   
    else  
    {  
        NSLog(@"typed");  
    }  
}  


-(void)searchBarTextDidBeginEditing:(UISearchBar *)theSearchBar  
{  
    NSLog(@"began");  // this executes as soon as i tap on the searchbar, so I'm guessing this is the place to put whatever solution is available  
}  
Hiren Dhamecha
  • 658
  • 5
  • 15
David Homes
  • 2,725
  • 8
  • 33
  • 53

10 Answers10

30

You can get around this by looping around the subviews in the UISearchBar until you find the text field. Its then just a matter of setting "enablesReturnKeyAutomatically" to NO. Incidentally the following code also is useful for setting the keyboard type.

  // loop around subviews of UISearchBar
  for (UIView *searchBarSubview in [searchBar subviews]) {    
    if ([searchBarSubview conformsToProtocol:@protocol(UITextInputTraits)]) {    
      @try {
        // set style of keyboard
        [(UITextField *)searchBarSubview setKeyboardAppearance:UIKeyboardAppearanceAlert];

        // always force return key to be enabled
        [(UITextField *)searchBarSubview setEnablesReturnKeyAutomatically:NO];
      }
      @catch (NSException * e) {        
        // ignore exception
      }
    }
  }
AndyDunn
  • 1,074
  • 1
  • 12
  • 19
24

Nowadays UISearchBar conforms to UITextInputTraits. You can simply set:

searchBar.enablesReturnKeyAutomatically = NO;

WARNING: While this compiles for iOS 7.0, it will crash at runtime. It only works for >=7.1.

The docs are not clear on this one, as only since 7.1, the UISearchBar implements the UITextInputTraits protocol, but it is not noted since which iOS version the protocol is adopted.

fabb
  • 11,660
  • 13
  • 67
  • 111
  • beautiful & simple! was coming back to this old question since i'm moving some oooooold apps to 64bits and forgot the solution for a specific use case – David Homes Apr 15 '17 at 10:58
10

The accepted answer doesn't seem to work anymore, so I made my own category that does seem to work:

@implementation UISearchBar (enabler)

- (void) alwaysEnableSearch {
    // loop around subviews of UISearchBar
    NSMutableSet *viewsToCheck = [NSMutableSet setWithArray:[self subviews]];
    while ([viewsToCheck count] > 0) {
        UIView *searchBarSubview = [viewsToCheck anyObject];
        [viewsToCheck addObjectsFromArray:searchBarSubview.subviews];
        [viewsToCheck removeObject:searchBarSubview];
        if ([searchBarSubview conformsToProtocol:@protocol(UITextInputTraits)]) {
            @try {
                // always force return key to be enabled
                [(UITextField *)searchBarSubview setEnablesReturnKeyAutomatically:NO];
            }
            @catch (NSException * e) {
                // ignore exception
            }
        }
    }
}
Kudit
  • 4,212
  • 2
  • 26
  • 32
  • 2
    this works too (at least on ios 9. not sure about the other): if ([self.searchBar respondsToSelector:NSSelectorFromString(@"searchField")]) { UITextField *searchTextField = ((UITextField*)[self.searchBar valueForKey:@"searchField"]); searchTextField.enablesReturnKeyAutomatically = NO; } – codrut Nov 02 '15 at 14:03
5

Simple and easy solution for iOS 10 on XCode 8.3.3, although it took some time to figure it out :)

@IBOutlet var searchBar: UISearchBar! {
    didSet {
        searchBar.returnKeyType = .done
        searchBar.enablesReturnKeyAutomatically = false
    }
}

Changes Search to Done. Enables Done without having to type anything in the search field. After that -> searchBar.resignFirstResponder() like so:

func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
    searchBar.resignFirstResponder()
}
Dusan Juranovic
  • 157
  • 2
  • 12
4

For iOS 8 and above you can use

[self.searchBar setReturnKeyType:UIReturnKeyDone];
[self.searchBar setEnablesReturnKeyAutomatically:NO];
Burhanuddin Sunelwala
  • 5,318
  • 3
  • 25
  • 51
3

Set enablesReturnKeyAutomatically to false

enablesReturnKeyAutomatically

searchBar.enablesReturnKeyAutomatically = false
2

This code display Search Button if you have empty string:

- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
    [itemSearchBar setShowsCancelButton:YES];
    UITextField *searchBarTextField = nil;
    for (UIView *subView in self.itemSearchBar.subviews)
    {
        for (UIView *sndSubView in subView.subviews)
        {
            if ([sndSubView isKindOfClass:[UITextField class]])
            {
                searchBarTextField = (UITextField *)sndSubView;
                break;
            }
        }
    }
    searchBarTextField.enablesReturnKeyAutomatically = NO;
    return YES;
}
halfer
  • 19,824
  • 17
  • 99
  • 186
Himanshu padia
  • 7,428
  • 1
  • 47
  • 45
  • This is more likely to break again if the view hierarchy changes. Recommend using a style like Gujamin's answer or a recursive function. – eselk Mar 13 '15 at 22:44
0

A simplest way and tricky is just put a blank when beginning editing search

-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
    //Add a blank character to hack search button enable
    searchBar.text = @" ";}
JasonD
  • 11
  • 3
0

Extension for Swift:

extension UISearchBar {
    var textField: UITextField? {
        return getTextField(inViews: subviews)
    }

    private func getTextField(inViews views: [UIView]?) -> UITextField? {
        guard let views = views else { return nil }

        for view in views {
            if let textField = (view as? UITextField) ?? getTextField(inViews: view.subviews) {
                return textField
            }
        }

        return nil
    }
}

Usage:

searchBar.textField?.returnKeyType = .Done
searchBar.textField?.enablesReturnKeyAutomatically = false
Anton Plebanovich
  • 1,296
  • 17
  • 17
0

Based on the Maps app, for example, it seems the pattern should be to have a cancel button near the textfield to get rid of the keyboard. With that said, one suggestion might be to have a custom UIButton placed right in that corner that looks just like the Done button.

Kind of a hacky solution...

Hope this helps!

donkim
  • 13,119
  • 3
  • 42
  • 47
  • mmmmmjm, not to convinced on that one (placing a button on top of that corner). I believe I saw once on the web how it was done but i haven't been able to find it again – David Homes Jan 20 '11 at 01:37
  • 1
    @AndyDunn, maaaan, after a looooong time I realized that your solution actually is the proper one! I apologize for not having it tried when you posted. Sorry big time. I always appreciate the time other put into helping others here – David Homes Aug 01 '11 at 21:59
  • Yep, it's a pattern that suits `UISearchDisplayController`-like search. Check iBooks, there's no _Cancel_ button there. – Rudolf Adamkovič Feb 02 '13 at 18:22