I\'d like to change the text from "Cancel" to "Done" of the Cancel button inside the UISearchBar
in iOS 8. I am using UISearchControll
For iOS 13 Support:
Swift:
UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).title = "Whatever"
Objective C:
[[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:[NSArray arrayWithObject:[UISearchBar class]]] setTitle:@"Whatever"]
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)
This worked for me in ios8 through ios13, 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 ;)
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:
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.
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,UINavigationButton in which UINavigationButton is subclass of UIButton.Check for View as UIButton and if yes then change property of UIButton.