How to change the default text of Cancel Button wh

2019-01-08 11:28发布

问题:

I am developing an Application where I wanted to change the text of Search String in the SearchBar. I wanted to change the text of Cancel Button Also which appears next to the SearchBar. Before entering any string in the search bar we wil get the Search String as the default string. I wanted to change the text of that string and when we click on that searchbar we get a cancel button next to searchbar and I wanted to change the text of that cancel button.

回答1:

You also need to have the "searchBar setShowsCancelButton" before the procedure.

- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
{
    [theSearchBar setShowsCancelButton:YES animated:NO];
    for (UIView *subView in theSearchBar.subviews){
        if([subView isKindOfClass:[UIButton class]]){
            [(UIButton*)subView setTitle:@"Done" forState:UIControlStateNormal];
        }
    }
}

Note also: use UIButton to avoid problems with Apple!



回答2:

Use the appearance proxy:

id barButtonAppearanceInSearchBar = [UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil];

[barButtonAppearanceInSearchBar setBackgroundImage:grayBackgroundImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[barButtonAppearanceInSearchBar setTitleTextAttributes:@{
                                      NSFontAttributeName : [UIFont fontWithName:@"HelveticaNeue-CondensedBold" size:20],
                                 NSForegroundColorAttributeName : [UIColor blackColor]
     } forState:UIControlStateNormal];
[barButtonAppearanceInSearchBar setTitle:@"X"];


回答3:

Solution for iOS 7. All credits for this go to Mr. Jesper Nielsen - he wrote the code.

-(void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
    UIButton *cancelButton;
    UIView *topView = theSearchBar.subviews[0];
    for (UIView *subView in topView.subviews) {
        if ([subView isKindOfClass:NSClassFromString(@"UINavigationButton")]) {
            cancelButton = (UIButton*)subView;
        }
    }
    if (cancelButton) {
        [cancelButton setTitle:@"YourTitle" forState:UIControlStateNormal];
    }

}


回答4:

If by "Search String", you mean the placeholder, then this should do it:

[searchBar setPlaceholder:@"Whatever you want"];

As for changing the text of the cancel button, that may be a bit more difficult. Apple does not use a standard UIBarButtonItem for this, or even a non-standard UIButton. Instead they use a UINavigationButton for the cancel button in the search bar. Since this is not a documented public class, attempting to modify it could very well get your app rejected from the App Store. If you do want to risk rejection, then you could search through the subviews of searchBar:

for(UIView *view in [searchBar subviews]) {
    if([view isKindOfClass:[NSClassFromString(@"UINavigationButton") class]]) {
        [(UIBarItem *)view setTitle:@"Whatever you want"];
    }
}

Note that the cancel button is loaded lazily, so you will have to do this modification when the search bar is activated by the user.



回答5:

In iOS 7 if you are using UISearchBar just write this code in searchBarTextDidBeginEditing: method

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:@"إلغاء" forState:UIControlStateNormal];
       }
}


回答6:

I would like to fix the UIAppearance technique, as yar1vn code won't work with Xcode 5. With the following you will have code that works perfectly for both iOS 6 and iOS 7.

First, you need to understand that the cancel button is a private UINavigationButton:UIButton. Hence, it is not an UIBarButtonItem. After some inspection, it appears that UINavigationButton will respond to those UIAppearance selectors:

// inherited from UINavigationButton
@selector(setTintColor:)
@selector(setBackgroundImage:forState:style:barMetrics:)
@selector(setBackgroundImage:forState:barMetrics:)
@selector(setTitleTextAttributes:forState:)
@selector(setBackgroundVerticalPositionAdjustment:forBarMetrics:)
@selector(setTitlePositionAdjustment:forBarMetrics:)
@selector(setBackButtonBackgroundImage:forState:barMetrics:)
@selector(setBackButtonTitlePositionAdjustment:forBarMetrics:)
@selector(setBackButtonBackgroundVerticalPositionAdjustment:forBarMetrics:)

// inherited from UIButton
@selector(setTitle:forState:)

Coincidentally, those selectors match those of a UIBarButtonItem. Meaning the trick is to use two separate UIAppearance to handle the private class UINavigationButton.

/* dual appearance technique by Cœur to customize a UINavigationButton */
Class barClass = [UISearchBar self];

UIBarButtonItem<UIAppearance> *barButtonItemAppearanceInBar = [UIBarButtonItem appearanceWhenContainedIn:barClass, nil];
[barButtonItemAppearanceInBar setTintColor:...];
[barButtonItemAppearanceInBar setBackgroundImage:... forState:... style:... barMetrics:...];
[barButtonItemAppearanceInBar setBackgroundImage:... forState:... barMetrics:...];
[barButtonItemAppearanceInBar setTitleTextAttributes:... forState:...];
[barButtonItemAppearanceInBar setBackgroundVerticalPositionAdjustment:... forBarMetrics:...];
[barButtonItemAppearanceInBar setTitlePositionAdjustment:... forBarMetrics:...];
[barButtonItemAppearanceInBar setBackButtonBackgroundImage:... forState:... barMetrics:...];
[barButtonItemAppearanceInBar setBackButtonTitlePositionAdjustment:... forBarMetrics:...];
[barButtonItemAppearanceInBar setBackButtonBackgroundVerticalPositionAdjustment:... forBarMetrics:...];

UIButton<UIAppearance> *buttonAppearanceInBar = [UIButton appearanceWhenContainedIn:barClass, nil];
[buttonAppearanceInBar setTitle:... forState:...];

Now, this technique works for the Cancel button, but it also works for the Back button if you change the barClass to [UINavigationBar self].



回答7:

This solution work for me - iOs7 and iOs8:

@interface ... : ...
@property (strong, nonatomic) IBOutlet UISearchBar *search; 
@end

and

- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
[searchBar setShowsCancelButton:YES animated:YES];

NSArray *searchBarSubViews = [[self.search.subviews objectAtIndex:0] subviews];
UIButton *cancelButton;
for (UIView *subView in searchBarSubViews) {
    if ([subView isKindOfClass:NSClassFromString(@"UINavigationButton")]) {
        cancelButton = (UIButton*)subView;
        break;
    }
}
if (cancelButton) {

    [cancelButton setTitle:@"New cancel" forState:UIControlStateNormal];

}
 //insert this two lines below if you have a button appearance like this "Ne...cel" 

[searchBar setShowsCancelButton:NO animated:YES];
[searchBar setShowsCancelButton:YES animated:YES]; 
}


回答8:

On iOS 7, if you've set displaysSearchBarInNavigationBar = YES on UISearchDisplayController, replacing the cancel button title via subview recursion or the appearance proxy will not work.

Instead, use your own bar button in viewDidLoad:

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.searchDisplayController.displaysSearchBarInNavigationBar = YES;
    UIBarButtonItem *barItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"A Custom Title", nil)
                                                                style:UIBarButtonItemStyleBordered
                                                               target:self
                                                               action:@selector(cancelButtonTapped:)];

    // NB: Order is important here.
    //     Only do this *after* setting displaysSearchBarInNavigationBar to YES
    //     as that's when UISearchDisplayController creates it's navigationItem
    self.searchDisplayController.navigationItem.rightBarButtonItem = barItem;
}


回答9:

Jeremytripp 's working Code in Swift

I couldn't find the same code in Swift so I "translated" it myself:

func searchDisplayControllerWillBeginSearch(controller: UISearchDisplayController) {
    self.searchDisplayController?.searchBar.showsCancelButton = true
    var cancelButton: UIButton
    var topView: UIView = self.searchDisplayController?.searchBar.subviews[0] as UIView
    for subView in topView.subviews {
        if subView.isKindOfClass(NSClassFromString("UINavigationButton")) {
        cancelButton = subView as UIButton
        cancelButton.setTitle("My Custom Title", forState: UIControlState.Normal)
        }
    }
}


回答10:

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.

Here is my change,

<key>CFBundleDevelopmentRegion</key>
<string>zh_CN</string>

after that, the default "Cancel" title will show as Chinese "取消". This change will also affect all the default region values, for example, the pasteboard operations' action titles on UITextField/UITextView will be localized, "Select" -> "选择", "Paste" -> "粘贴"...

By the way, the Info.plist file could be localized perfectly.

Enjoy!



回答11:

Instead of referencing the non-public UINavigationButton class, I did the following. I'm hoping that it will make it through App Store review!

for (id subview in searchBar.subviews) {
    if ([subview respondsToSelector:@selector(setTitle:)]) {
        [subview setTitle:@"Map"];
    }
}


回答12:

If you're still having trouble with changing the Cancel button in iOS7, this is currently working for me:

-(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:@"Hi" forState:UIControlStateNormal];
    }
}


回答13:

if the SearchBar is in the navigationBar, the code will be different than the usual answer; You need to search for NavigationBar's subviews instead.

-(void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller{
UINavigationBar * navigationBar =  self.navigationController.navigationBar;

for (UIView *subView in navigationBar.subviews){
    if([subView isKindOfClass:NSClassFromString(@"UINavigationButton")]){
        [(UIButton*)subView setTitle:@"İptal" forState:UIControlStateNormal];
    }
}}

and This work in iOS7+ , if you still can't set the title you should learn view debugging - This is how I solved this problem of mine.

This brief tutorial outlines the key points of View-Debugging very well:

http://www.raywenderlich.com/98356/view-debugging-in-xcode-6



回答14:

Working short code in Swift 2.1 (iOS7-9 tested)

@IBOutlet weak var searchBar: UISearchBar!
func enableSearchBarCancelButton(enable: Bool, title: String? = nil) {
    searchBar?.showsCancelButton = enable
    if enable {
        if let _cancelButton = searchBar?.valueForKey("_cancelButton"),
            let cancelButton = _cancelButton as? UIButton {
                cancelButton.enabled = enable //comment out if you want this button disabled when keyboard is not visible
                if title != nil {
                    cancelButton.setTitle(title, forState: UIControlState.Normal)
                }
        }
    }
}