61

In the UISearchBar control, is the a way to change the Search key title for the keyboard to Done?

Jim B
  • 2,267
  • 6
  • 24
  • 26

10 Answers10

99

For a searchbar named tablesearchbar:

// Set the return key and keyboard appearance of the search bar
        for (UIView *searchBarSubview in [tableSearchBar subviews]) {

            if ([searchBarSubview conformsToProtocol:@protocol(UITextInputTraits)]) {

                @try {

                    [(UITextField *)searchBarSubview setReturnKeyType:UIReturnKeyDone];
                    [(UITextField *)searchBarSubview setKeyboardAppearance:UIKeyboardAppearanceAlert];
                }
                @catch (NSException * e) {

                    // ignore exception
                }
            }
        }
RunLoop
  • 20,288
  • 21
  • 96
  • 151
  • Will this get past the App Store approval process? – zekel Jun 17 '10 at 00:26
  • 4
    As no private APIs are accessed, approval should not be withheld – RunLoop Jun 17 '10 at 05:53
  • 2
    Great answer. Extra caveat: instead of using @try-@catch (which we know in objective-C aren't so cheap and well optimized), I would prefer adding a second condition to the if statement: && [searchBarSubview isKindOfClass:[UITextField class]] in order to get rid of the @try-catch. – Andrea Sprega Jun 27 '13 at 15:07
  • 6
    Looping over subviews didn't work for me in iOS 7, but looping over subviews of subviews did (see my answer). – Gregory Cosmo Haun Sep 05 '13 at 16:34
  • //if you're not on the main thread, insert this after 'setReturnKeyType': ______ [(UITextField *)searchBarSubview performSelectorOnMainThread:@selector(reloadInputViews) withObject:nil waitUntilDone:NO]; – codrut Oct 08 '13 at 13:19
  • Not working for me, I have posted [my question](http://stackoverflow.com/questions/28577158/uisearchbar-returnkeytype-not-working-for-ios-8). Please help me – Pradip Vanparia Feb 18 '15 at 06:29
52

At least for iOS 8, simply:

    [self.searchBar setReturnKeyType:UIReturnKeyDone];
pickwick
  • 3,134
  • 22
  • 30
43

As of iOS 7 beta 5, Run Loop's answer didn't work for me, but this did:

for(UIView *subView in [searchBar subviews]) {
    if([subView conformsToProtocol:@protocol(UITextInputTraits)]) {
         [(UITextField *)subView setReturnKeyType: UIReturnKeyDone];
    } else {
        for(UIView *subSubView in [subView subviews]) {
            if([subSubView conformsToProtocol:@protocol(UITextInputTraits)]) {
                [(UITextField *)subSubView setReturnKeyType: UIReturnKeyDone];
            }
        }      
    }
}
Dom
  • 2,569
  • 1
  • 18
  • 28
Gregory Cosmo Haun
  • 1,499
  • 17
  • 25
  • 5
    Just in case it isn't clear, the reason if/else is used is the if is for iOS 6 backward compatibility and the else is for iOS 7. – James Kuang Sep 18 '13 at 14:13
18

For Swift to change return key of UISearchBar

searchBar.returnKeyType = UIReturnKeyType.done

enum available are as below

public enum UIReturnKeyType : Int {

    case default
    case go
    case google
    case join
    case next
    case route
    case search
    case send
    case yahoo
    case done
    case emergencyCall
    @available(iOS 9.0, *)
    case continue
}
AamirR
  • 11,672
  • 4
  • 59
  • 73
Hardik Thakkar
  • 15,269
  • 2
  • 94
  • 81
18

One more useful hint, to the Run Loop code (in "@try") section.

This enabled "Done" button when text field is empty:

UITextField *tf = (UITextField *)searchBarSubview;
tf.enablesReturnKeyAutomatically = NO;
theWalker
  • 2,022
  • 2
  • 18
  • 27
3

Just a reminder! If you searchBar stays as first responder, after you change your returnKeyType, you need to dismiss your keyboard and pop it up again to see the changes.

search.resignFirstResponder()
searchBar.returnKeyType = UIReturnKeyType.Done
search.becomeFirstResponder()
Codingpan
  • 318
  • 2
  • 6
1

As it is a protocol with optional methods, you should test each method separately instead of try-catching.

for (UIView *searchBarSubview in searchBar.subviews)
{
    if ([searchBarSubview conformsToProtocol:@protocol(UITextInputTraits)])
    {
        // keyboard appearance
        if ([searchBarSubview respondsToSelector:@selector(setKeyboardAppearance:)])
            [(id<UITextInputTraits>)searchBarSubview setKeyboardAppearance:UIKeyboardAppearanceAlert];
        // return key 
        if ([searchBarSubview respondsToSelector:@selector(setReturnKeyType:)])
            [(id<UITextInputTraits>)searchBarSubview setReturnKeyType:UIReturnKeyDone];
        // return key disabled when empty text
        if ([searchBarSubview respondsToSelector:@selector(setEnablesReturnKeyAutomatically:)])
            [(id<UITextInputTraits>)searchBarSubview setEnablesReturnKeyAutomatically:NO];
        // breaking the loop when we are done
        break;
    }
}

This will work for iOS <= 6. For iOS >= 7, you need to loop in searchBar.subviews[0].subviews.

Cœur
  • 37,241
  • 25
  • 195
  • 267
0

I tried all the solutions shown here, and none of them worked for my UISearchBar (xcode5 compiling for iOS7). I ended up with this recursive function which worked for me:

- (void)fixSearchBarKeyboard:(UIView*)searchBarOrSubView {

    if([searchBarOrSubView conformsToProtocol:@protocol(UITextInputTraits)]) {
        if ([searchBarOrSubView respondsToSelector:@selector(setKeyboardAppearance:)])
            [(id<UITextInputTraits>)searchBarOrSubView setKeyboardAppearance:UIKeyboardAppearanceAlert];
        if ([searchBarOrSubView respondsToSelector:@selector(setReturnKeyType:)])
            [(id<UITextInputTraits>)searchBarOrSubView setReturnKeyType:UIReturnKeyDone];
        if ([searchBarOrSubView respondsToSelector:@selector(setEnablesReturnKeyAutomatically:)])
            [(id<UITextInputTraits>)searchBarOrSubView setEnablesReturnKeyAutomatically:NO];
    }

    for(UIView *subView in [searchBarOrSubView subviews]) {
        [self fixSearchBarKeyboard:subView];
    }
}

I then called it like so:

_searchBar = [[UISearchBar alloc] init];
[self fixSearchBarKeyboard:_searchBar];
dacoinminster
  • 3,637
  • 2
  • 18
  • 23
  • With Xcode 5 + iOS7, text input will be in a sub-subview instead of a subview. So basically you used my Xcode 4 solution and added a recursive call. For best performances, you can test for iOS version, and if it's iOS7, you browse through `subviews[0].subviews` instead of `subviews`. – Cœur Jan 15 '14 at 13:21
0

Just for covering all the iOS versions:

NSArray *subviews = [[[UIDevice currentDevice] systemVersion] floatValue] < 7 ? _searchBar.subviews : _searchBar.subviews[0].subviews;

for (UIView *subview in subviews)
{
    if ([subview conformsToProtocol:@protocol(UITextInputTraits)])
    {
        UITextField *textField = (UITextField *)subview;
        [textField setKeyboardAppearance: UIKeyboardAppearanceAlert];
        textField.returnKeyType = UIReturnKeyDone;
        break;
    }
}
Zaraki
  • 3,720
  • 33
  • 39
0

Since the Alert-style keyboards are semi-transparent, I can see my view behind it. It doesn't look very good since I have multiple elements behind the keyboard that makes it hard for the keys to stand out. I wanted an all-black keyboard.

So I animated a black UIImageView into position behind the keyboard when text is edited. This gives the appearance of an all-black keyboard.

- (void)textFieldDidBeginEditing:(UITextField *)textField {

    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.25]; 

    blackBoxForKeyboard.frame = CGRectMake(0, 377, 320, 216);
    [UIView commitAnimations]; 

}
RyeMAC3
  • 1,023
  • 1
  • 10
  • 17