Change UISearchBar cancel button text in iOS 8

2019-01-31 12:45发布

问题:

I'd like to change the text from ¨Cancel¨to ¨Done¨ of the Cancel button inside the UISearchBar in iOS 8. I am using UISearchController. I've tried different approaches for iOS 6 and iOS 7 and they do not work. Has anybody done this?

回答1:

Objective-C:

[searchBar setValue:@"customString" forKey:@"_cancelButtonText"];

Swift:

searchBar.setValue("customString", forKey:"_cancelButtonText")


回答2:

This worked for me in ios8, did not try in ios7, but should do the trick, beware of placing this line in the early times of the app cycle (eg : appDelegate)

[[UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil] setTitle:@"Annuler"];

and as of ios9 you could also use

[[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setTitle:@"Annuler"];

Swift version:

UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).title = "Annuler"

Hope that helps ;)



回答3:

Found it!. in iOS 8, the cancel button is under the key "cancelButton". I used UISearchBar delegate searchBarTextDidBeginEditing to make the change.

func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
    let uiButton = searchBar.valueForKey("cancelButton") as UIButton
    uiButton.setTitle("Done", forState: UIControlState.Normal)

}


回答4:

Swift 3.0:

In your AppDelegate add this:

UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).title = "my text"


回答5:

 for view in (UISearchBar.subviews[0]).subviews{
             if let button = view as? UIButton{
             button.setTitleColor(UIColor.whiteColor(), forState: .Normal)
             button.setTitle("Cancel", forState:.Normal)
            }
     }

self.subviews[0]).subviews contain UISearchBarBackground,UISearchBarTextField,UINavigationButto‌​n in which UINavigationButton is subclass of UIButton.Check for View as UIButton and if yes then change property of UIButton.



回答6:

In Swift:

searchBar.setValue("customString", forKey: "_cancelButtonText")

Based on Burhanuddin Sunelwala answer.



回答7:

In Swift4

Change Title:

(searchBar.value(forKey: "cancelButton") as! UIButton).setTitle("Done", for: .normal)

Change Color:

(searchBar.value(forKey: "cancelButton") as! UIButton).setTitleColor(UIColor.blue, for: .normal)



回答8:

I was having trouble getting this to work for a UISearchBar within a UISearchController. The text didn't change the first time the cancel button was shown but it did the second time.

That is until I saw @polo987's answer. Here's what I did that worked:

UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).title = "Done"


回答9:

I have added titleLabel.font to the mix...

This goes straight into my ViewDidLoad() {

        let searchFont = UIFont(name: "BrandonGrotesque-Medium", size: 12)
        let textFieldSearchBar = self.searchBar.valueForKey("searchField") as! UITextField
        textFieldSearchBar.font = searchFont
        let cancelButton = searchBar.valueForKey("cancelButton") as! UIButton
        cancelButton.setTitle("Done", forState: .Normal)
        cancelButton.titleLabel!.font = searchFont


回答10:

I know this may seem to be a bit irrelevant but in my opinion this is safer than using private apis and more efficient than taking a dive into the unknown views. This solution makes sense only if you have your own localisation engine and you do want Apple to follow your mechanism all over the app. Basically my idea is to switch the language the iOS SDK uses to localise the button by altering the "AppleLanguages" key in the NSUserDefaults. You can go here for more information about how this works.

[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];

Put this code to use the English localisation and a French fallback no matter what language is set on the phone. This only takes effect within the app.



回答11:

Here is Swift solution:

for (view) in _searchController.searchBar.subviews {
    for (subview) in view.subviews {
        if (subview.isKindOfClass(UIButton.self)) {
            let cancelButton = subview as! UIButton
            cancelButton.setTitle("BlaBla", forState: .Normal)
            break
        }
    }
}


回答12:

Swift 4.2, 4.0+

A custom class to customize the most common elements in search bar.

class SearchBar: UISearchBar {

    private enum SubviewKey: String {
        case searchField, clearButton, cancelButton,  placeholderLabel
    }

    // Button/Icon images
    public var clearButtonImage: UIImage?
    public var resultsButtonImage: UIImage?
    public var searchImage: UIImage?

    // Button/Icon colors
    public var searchIconColor: UIColor?
    public var clearButtonColor: UIColor?
    public var cancelButtonColor: UIColor?
    public var capabilityButtonColor: UIColor?

    // Text
    public var textColor: UIColor?
    public var placeholderColor: UIColor?
    public var cancelTitle: String?

    // Cancel button to change the appearance.
    public var cancelButton: UIButton? {
        guard showsCancelButton else { return nil }
        return self.value(forKey: SubviewKey.cancelButton.rawValue) as? UIButton
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        if let cancelColor = cancelButtonColor {
            self.cancelButton?.setTitleColor(cancelColor, for: .normal)
        }
        if let cancelTitle = cancelTitle {
            self.cancelButton?.setTitle(cancelTitle, for: .normal)
        }

        guard let textField = self.value(forKey: SubviewKey.searchField.rawValue) as? UITextField else { return }

        if let clearButton = textField.value(forKey: SubviewKey.clearButton.rawValue) as? UIButton {
            update(button: clearButton, image: clearButtonImage, color: clearButtonColor)
        }
        if let resultsButton = textField.rightView as? UIButton {
            update(button: resultsButton, image: resultsButtonImage, color: capabilityButtonColor)
        }
        if let searchView = textField.leftView as? UIImageView {
            searchView.image = (searchImage ?? searchView.image)?.withRenderingMode(.alwaysTemplate)
            if let color = searchIconColor {
                searchView.tintColor = color
            }
        }
        if let placeholderLabel =  textField.value(forKey: SubviewKey.placeholderLabel.rawValue) as? UILabel,
            let color = placeholderColor {
            placeholderLabel.textColor = color
        }
        if let textColor = textColor  {
            textField.textColor = textColor
        }
    }

    private func update(button: UIButton, image: UIImage?, color: UIColor?) {
        let image = (image ?? button.currentImage)?.withRenderingMode(.alwaysTemplate)
        button.setImage(image, for: .normal)
        button.setImage(image, for: .highlighted)
        if let color = color {
            button.tintColor = color
        }
    }
}

Usage:

class ViewController: UIViewController {

    @IBOutlet private weak var searchBar: SearchBar!

    override func viewDidLoad() {
        super.viewDidLoad()

        searchBar.clearButtonColor      = .purple
        searchBar.cancelButtonColor     = .magenta
        searchBar.searchIconColor       = .red
        searchBar.placeholderColor      = .green
        searchBar.textColor             = .orange
        searchBar.capabilityButtonColor = .green
    }
}

Result: