8

I wish to change the title of the cancel button in iOS. I have been using this previously:

- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller{
  self.searchDisplayController.searchBar.showsCancelButton = YES;
  UIButton *cancelButton = nil;
  for (UIView *subView in self.searchDisplayController.searchBar.subviews) {
     if ([subView isKindOfClass:NSClassFromString(@"UIButton")]) {
         cancelButton = (UIButton*)subView;
     }
  }
  [cancelButton setTitle:@"Annuller" forState:UIControlStateNormal];
}

But it doesnt seem to work in iOS7. Any Suggestions?

Danienllxxox
  • 423
  • 1
  • 7
  • 13
  • put the `[cancelButton setTitle:@"Annuller" forState:UIControlStateNormal];` inside the if condition. also check this same question [Customizing Cancel button of UISearchBar](http://stackoverflow.com/a/12265279/1280373) – Nitin Gohel Sep 23 '13 at 09:53
  • If you just want to **localized** the default "Cancel" title for cancel button, I prefer to change the value of **CFBundleDevelopmentRegion** key from en to your localized region in Info.plist file in project. See detail answer from here: http://stackoverflow.com/a/37427398/1677041 – Itachi May 25 '16 at 03:41

13 Answers13

12

You need to search for the button recursively. This should be a fail-safe way to do it:

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self convertButtonTitle:@"Cancel" toTitle:@"Annuller" inView:self.searchBar];
}

- (void)convertButtonTitle:(NSString *)from toTitle:(NSString *)to inView:(UIView *)view
{
    if ([view isKindOfClass:[UIButton class]])
    {
        UIButton *button = (UIButton *)view;
        if ([[button titleForState:UIControlStateNormal] isEqualToString:from])
        {
            [button setTitle:to forState:UIControlStateNormal];
        }
    }

    for (UIView *subview in view.subviews)
    {
        [self convertButtonTitle:from toTitle:to inView:subview];
    }
}

I've tested this on iOS 7 only, but it works and should do so for iOS 6 too.

Guy Kogus
  • 7,251
  • 1
  • 27
  • 32
  • 1
    Tested on both 6 and 7. Works perfectly. Thank you very much! – Crazy Yoghurt Oct 03 '13 at 11:39
  • I would if I could, but I haven't asked question, just wanted to let others know, that your code works :) – Crazy Yoghurt Oct 03 '13 at 14:29
  • 2
    This won't work if the user is running iOS in any language other than English. – Mikkel Selsøe Jan 27 '14 at 15:16
  • I've assumed that the app is only localised to English. If that's the case the language of the device won't affect the language of the cancel button, and this code will work just fine. If you need to handle localised apps let me know, I'll update the answer :) – Guy Kogus Jan 27 '14 at 17:52
  • This method works in iOS7.1, however you need to add: [self.searchBar setShowsCancelButton:YES] in your viewDidLoad method. This method might be a hack, but the UIAppearance method seems to crash iOS 7.0.x (although that method also works in iOS 7.1.x) – siburb Apr 11 '14 at 03:42
  • Doesn't work on a Russian locale in any iOS version. Too pity. – Sergey Grischyov Apr 20 '14 at 18:55
10

simply do this code for it:-

- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
    /* when user start editing in serchbar this method will display cancel button and disable the autocorrection functionality */

    srcbar.showsCancelButton = YES;

    for (UIView *subView in searchBar.subviews) {
        if ([subView isKindOfClass:[UIButton class]]) {
           UIButton *cancelButton = (UIButton*)subView;

            [cancelButton setTitle:@"hi" forState:UIControlStateNormal];
        }
    }
    srcbar.autocorrectionType = UITextAutocorrectionTypeNo;

}

Not test in iOS7 but this working fine in iOS6 hope this working for you.

OUTPUT IS:-

enter image description here

Nitin Gohel
  • 49,482
  • 17
  • 105
  • 144
  • 1
    I have used this to update the code on a tutorial: http://ios-blog.co.uk/tutorials/quick-ios-tip-change-the-title-of-cancel-button-in-uisearchbar/ and you have been mentioned. Thank you – Danienllxxox Sep 23 '13 at 10:20
  • have you check with Break Point `searchBarTextDidBeginEditing` is calling or not? check properly that you give the delegate of you SeachBar? @RameezHussain Because the OP say's it working in iOS7 – Nitin Gohel Sep 24 '13 at 10:45
  • It's being called once and it doesn't change the appearance then. – Rameez Hussain Sep 24 '13 at 10:57
  • 11
    [[UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil] setTitle:@"YourNewTextHere"]; just use this of iOS 7 – Salih Ozdemir Mar 16 '14 at 23:37
  • 1
    I really don't think that looping through all sub-views (of a private view hierarchy) in the hope of finding the view that we want (and hope is of the class we want) can be modified - this kind of solution might work for the moment, but if ever Apple changes their view hierarchy (which is more than possible) then you will be left with a broken app. – Rupert Sep 01 '14 at 14:19
  • Not working anymore. For latest swift 3.0 please see http://stackoverflow.com/a/40260490/2545465 – Rajan Maheshwari Oct 26 '16 at 10:59
10

here is my solution for both ios6 & ios7

#define IS_IOS7 (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1)
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
{
    self.searchDisplayController.searchBar.showsCancelButton = YES;

    UISearchBar *searchBar = self.searchDisplayController.searchBar;
    UIView *viewTop = IS_IOS7 ? searchBar.subviews[0] : searchBar;
    NSString *classString = IS_IOS7 ? @"UINavigationButton" : @"UIButton";

    for (UIView *subView in viewTop.subviews) {
        if ([subView isKindOfClass:NSClassFromString(classString)]) {
            UIButton *cancelButton = (UIButton*)subView;
            [cancelButton setTitle:@"your title" forState:UIControlStateNormal];
        }
    }
}
nahung89
  • 7,745
  • 3
  • 38
  • 40
8

in order to make it work on iOS7, you have to search in the subview of search bar:

//iOS 7 hack
searchBar.showsCancelButton = YES;
UIView* view=searchBar.subviews[0];
for (UIView *subView in view.subviews) {
    if ([subView isKindOfClass:[UIButton class]]) {
        UIButton *cancelButton = (UIButton*)subView;

        [cancelButton setTitle:@"Anuluj" forState:UIControlStateNormal];
    }
}
Michał Zygar
  • 4,052
  • 1
  • 23
  • 36
4

Put this line in appDelegate

[[UIButton appearanceWhenContainedIn:[UISearchBar class], nil] setTitle:@"Your Title" forState:UIControlStateNormal];

Hiren Panchal
  • 2,963
  • 1
  • 25
  • 21
  • Or with iOS 9 and Swift: `UIButton.appearanceWhenContainedInInstancesOfClasses([UISearchBar.self]).setTitle("Your Title", forState: .Normal)` – Jim Rhoades Oct 13 '15 at 19:11
4

For Swift 3.0

This is working fine.

func setSearchButtonText(text:String,searchBar:UISearchBar) {

    for subview in searchBar.subviews {
        for innerSubViews in subview.subviews {
            if let cancelButton = innerSubViews as? UIButton {
                cancelButton.setTitleColor(UIColor.white, for: .normal)
                cancelButton.setTitle(text, for: .normal)
            }
        }
    }

}

And call the method

setSearchButtonText(text: "Done", searchBar: yourSearchBar)

Here is the output

enter image description here

Twitter khuong291
  • 11,328
  • 15
  • 80
  • 116
Rajan Maheshwari
  • 14,465
  • 6
  • 64
  • 98
1

If you just want to change the "Cancel" text to the same in your locale, the proper way I think is using localization. Here is how:

  1. open your project in the Finder, locate the en.lproj directory
  2. rename it to your locale, or duplicate it if you have to support multiple languages
  3. remove any file references it may have contained in Xcode (they should look red)
  4. drag the same files from Finder from the new directory to Xcode
  5. (not sure this is necessary) edit your Info.plist and add these lines:

    • Localization native development region: your region (for example: en)
    • Localizations: for example English

Note: it does not work in Simulator, test it on the device!

(Source: http://www.ibabbleon.com/iphone_app_localization.html)

gklka
  • 2,459
  • 1
  • 26
  • 53
0

@Nitin Gohel Like so?

- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller{
  self.searchDisplayController.searchBar.showsCancelButton = YES;
  UIButton *cancelButton = nil;
  for (UIView *subView in self.searchDisplayController.searchBar.subviews) {
     if ([subView isKindOfClass:NSClassFromString(@"UIButton")]) {
         cancelButton = (UIButton*)subView;

         [cancelButton setTitle:@"Annuller" forState:UIControlStateNormal];
     }
 }

}
Danienllxxox
  • 423
  • 1
  • 7
  • 13
  • This works perfectly. Perhaps, the bad thing is I see that the TextColor of the cancel Button being changed. I tried to reapply with [cancelButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; , it doesn't work, also I see it takes color of Search Bar BarTint rather than SearchBar Tint color. – Vacca Oct 29 '14 at 14:09
0

It seems like "self.searchDisplayController.searchBar.subviews" just return the "searchBar" itself. I tried bellow, and it works!

for (UIView *searBarView in [self.searchDisplayController.searchBar subviews])
{
    for (UIView *subView in [searBarView subviews]) 
    {
        if ([subView isKindOfClass:[UIButton class]])
        {
            UIButton *cancleButton = (UIButton *)subView;
            [cancleButton setTitle:@"hi" forState:UIControlStateNormal];
        }
    }

}
0

Before search started, in UISearchBarDelagate or UISearchDisplayControllerDelegate do:

[self.searchDisplayController.searchBar.subviews enumerateObjectsUsingBlock:^(UIButton *subview, NSUInteger idx, BOOL *stop) {
            if ([subview isKindOfClass:[UIButton class]]) {
                [subview setTitle:@"OK" forState:UIControlStateNormal];
                *stop = YES;
            }
        }];
iiFreeman
  • 5,165
  • 2
  • 29
  • 42
0

For iOS7, this works.

-(void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller{
    self.searchDisplayController.searchBar.showsCancelButton = YES;
    UIButton *cancelButton;
    UIView *topView = self.searchDisplayController.searchBar.subviews[0];
    for (UIView *subView in topView.subviews) {
        if ([subView isKindOfClass:NSClassFromString(@"UINavigationButton")]) {
            cancelButton = (UIButton*)subView;
        }
    }
    if (cancelButton) {
      //Set the new title of the cancel button
        [cancelButton setTitle:@"YourTitle" forState:UIControlStateNormal];
    }
}
jeremytripp
  • 1,038
  • 1
  • 11
  • 25
0

Refer to @Salih's solution above, I used this code and work perfect! Just call the method setupAppearance in AppDelegate.m when app launching.

- (void)setupAppearance
{
   id appearance = nil;

   if (IOS9_OR_LATER) {
       appearance = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]];
   } else {
       appearance = [UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil];
   }

   [appearance setTitle:@"CANCEL"];
}
Itachi
  • 5,777
  • 2
  • 37
  • 69
0

Chiming in with the code I used inside the UIKitUISearchResultsUpdating protocol method updateSearchResults(for searchController: UISearchController):

if let cancelButton : UIButton = searchController.searchBar.value(forKey: "_cancelButton") as? UIButton {
    cancelButton.setTitle("Back", for: UIControlState.normal)
}

(iOS 10, Swift 3.0)

Code Roadie
  • 673
  • 9
  • 16