How to save the cancel button in the search bar when the keyboard is rejected?

enter image description hereenter image description here

I am trying to achieve the same effect as the Apple Contacts application (left screenshot). The cancel button in the UISearchBar is enabled, even if the keyboard is rejected. My application behaves differently (right screenshot). The cancel button is automatically disabled when the keyboard is rejected. The user must press the cancel button once to turn it on, and then again to actually cause the dismissal. This is not a good user interface. How will I always keep the cancel button on, like the Apple Contacts app?

Technical details:

I do not use UISearchDisplayController due to some design requirements. This is just a UISearchBar with my own custom search controller. The cancel button is displayed using [self.searchBar showsCancelButton:YES animated:YES] . The keyboard is rejected using [self.searchBar resignFirstResponder] .

+14
source share
8 answers

Calling [self.searchBar resignFirstResponder] will disable the cancel button. Therefore, you should always update the cancel button to enable it after the call.

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 a problem. Because it is also called .resignFirstResponder if there is a UITextField contained in the UISearchBar inside the view.

https://developer.apple.com/reference/uikit/uiview/1619630-endediting

+12
source

You can use the runtime API to access the cancel button.

 UIButton *btnCancel = [self.searchBar valueForKey:@"_cancelButton"]; [btnCancel setEnabled:YES]; 

As for your question, you cannot turn on the cancel button when the keyboard is rejected, for example, there is no callback.

+5
source

For Swift 4.0

 if let cancelButton : UIButton = searchBar.value(forKey: "cancelButton") as? UIButton{ cancelButton.isEnabled = true } 
+5
source

Since iOS 7, all subordinates of UISearchBar are one level deeper. This should work:

 for (UIView *subView in searchBar.subviews) { for (UIView *secondLevelSubview in subView.subviews) { if ([view isKindOfClass:[UIButton class]]) { [(UIButton *)view setEnabled:YES]; } } 

Still hacked and can easily break in the next version of iOS.

+3
source

You can do it:

 - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { [self enableCancelButton]; } - (void)enableCancelButton { for (UIView *view in _seachBar.subviews) { if ([view isKindOfClass:[UIButton class]]) { [(UIButton *)view setEnabled:YES]; } } } 

BUT , this is a pretty hacky method, and I'm pretty sure that it generally frowned on Apple and could potentially lead to a rejection of the application. To my knowledge, there seems to be no other way to do what you are trying to do.

+1
source

Inject the following searchBarShouldEndEditing delegate method into your code. Hope this helps.

 (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar { [[searchBar valueForKey:@"_cancelButton"] setEnabled:YES]; return YES; } 
+1
source

Here's a recursive solution that works for me.

func enableButtons(_ view:UIView) { for subView in view.subviews { enableButtons(subView) } if let buttonView = view as? UIButton { buttonView.isEnabled = true } }

+1
source

Here is an easy way:

 searchBar.resignFirstResponder() (searchBar.value(forKey: "_cancelButton") as? UIButton)?.isEnabled = true 
0
source

Source: https://habr.com/ru/post/970418/


All Articles