Implement the below searchBarShouldEndEditing delegate method in your code. Hope it will helpful.
(BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
{
[[searchBar valueForKey:@"_cancelButton"] setEnabled:YES];
return YES;
}
Call to [self.searchBar resignFirstResponder]
will make the cancel button disabled. Hence, you should always update cancel button to enable after calling it.
Objective-C
[searchBar resignFirstResponder];
UIButton *cancelButton = (UIButton *)[searchBar valueForKey:@"cancelButton"];
[cancelButton setEnabled:YES];
Swift
searchBar.resignFirstResponder()
if let cancelButton = searchBar.value(forKey: "cancelButton") as? UIButton
cancelButton.isEnabled = true
}
In my experience, view.endEditing(true)
is the problem. Because it's also called .resignFirstResponder
if there's a UITextField inside the view, which is contained in UISearchBar.
https://developer.apple.com/reference/uikit/uiview/1619630-endediting
This Worked For me
// ViewdidLoad()
SearchBar.enableCancelButton(in: ParentViewOfSearchBar)
For Swift 4.0
if let cancelButton : UIButton = searchBar.value(forKey: "cancelButton") as? UIButton{
cancelButton.isEnabled = true
}
Try this simple solution, works perfect for me
extension UISearchBar {
func enableCancelButton(in view: UIView) {
view.subviews.forEach {
enableCancelButton(in: $0)
}
if let cancelButton = view as? UIButton {
cancelButton.isEnabled = true
cancelButton.isUserInteractionEnabled = true
}
}
}
extension ViewController: UISearchBarDelegate {
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
DispatchQueue.main.async {
searchBar.enableCancelButton(in: searchBar)
}
}
}
This is what worked for me to handle any dismissal such as searchBar.resignFirstResponder()
, view.endEditing(false)
, interactive swipe to dismiss, presenting a view controller, etc.
extension ViewController: UISearchBarDelegate {
func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool {
//cancel button becomes disabled when search bar isn't first responder, force it back enabled
DispatchQueue.main.async {
if let cancelButton = searchBar.value(forKey: "cancelButton") as? UIButton {
cancelButton.isEnabled = true
}
}
return true
}
}
Making sure to set searchBar.delegate = self
.