如何使用UISearchBar启用取消button?

在iPhone上的联系人应用程序中,如果您inputsearch词,然后点击“search”button,键盘被隐藏,但取消button仍处于启用状态。 在我的应用程序中,当我呼叫resignFirstResponder时取消button被禁用。

任何人都知道如何隐藏键盘,同时保持取消button处于启用状态?

我使用下面的代码:

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { [searchBar resignFirstResponder]; } 

键盘滑出视图,但search文本字段右侧的“取消”button被禁用,因此我无法取消search。 联系人应用程序将取消button保持在启用状态。

我想也许有一个解决scheme是潜入searchBar对象,并在实际文本字段上调用resignFirstResponder,而不是search栏本身。

任何input赞赏。

尝试这个

 for(id subview in [yourSearchBar subviews]) { if ([subview isKindOfClass:[UIButton class]]) { [subview setEnabled:YES]; } } 

这个方法在iOS7中工作。

 - (void)enableCancelButton:(UISearchBar *)searchBar { for (UIView *view in searchBar.subviews) { for (id subview in view.subviews) { if ( [subview isKindOfClass:[UIButton class]] ) { [subview setEnabled:YES]; NSLog(@"enableCancelButton"); return; } } } } 

(也请务必在使用[_searchBar resignFirstResponder]之后的任何地方调用它。)

当您开始滚动表格而不是点击“search”button时,接受的解决scheme将不起作用。 在这种情况下,“取消”button将被禁用。

这是我的解决scheme,每次使用KVO禁用时,都会重新启用“取消”button。

 - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; // Search for Cancel button in searchbar, enable it and add key-value observer. for (id subview in [self.searchBar subviews]) { if ([subview isKindOfClass:[UIButton class]]) { [subview setEnabled:YES]; [subview addObserver:self forKeyPath:@"enabled" options:NSKeyValueObservingOptionNew context:nil]; } } } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; // Remove observer for the Cancel button in searchBar. for (id subview in [self.searchBar subviews]) { if ([subview isKindOfClass:[UIButton class]]) [subview removeObserver:self forKeyPath:@"enabled"]; } } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { // Re-enable the Cancel button in searchBar. if ([object isKindOfClass:[UIButton class]] && [keyPath isEqualToString:@"enabled"]) { UIButton *button = object; if (!button.enabled) button.enabled = YES; } } 

从iOS 6开始,button看起来像UINavigationButton(私有类),而不是UIButton。

我已经调整了上面的例子看起来像这样。

 for (UIView *v in searchBar.subviews) { if ([v isKindOfClass:[UIControl class]]) { ((UIControl *)v).enabled = YES; } } 

但是,这显然是脆弱的,因为我们正在与内部打交道。 它也可以启用更多的button,但它为我工作,直到find一个更好的解决scheme。

我们应该问苹果揭露这一点。

这似乎适用于我(在viewDidLoad):

 __unused UISearchDisplayController* searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self]; 

我意识到我应该正确使用UISearchDisplayController,但是这对我当前的实现来说是一个简单的修复。

您可以使用运行时API访问取消button。

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

通过在UISearchBar上实现这个简单类别,我扩展了已经发布的其他人。

的UISearchBar + alwaysEnableCancelButton.h

 #import <UIKit/UIKit.h> @interface UISearchBar (alwaysEnableCancelButton) @end 

的UISearchBar + alwaysEnableCancelButton.m

 #import "UISearchBar+alwaysEnableCancelButton.h" @implementation UISearchBar (alwaysEnableCancelButton) - (BOOL)resignFirstResponder { for (UIView *v in self.subviews) { // Force the cancel button to stay enabled if ([v isKindOfClass:[UIControl class]]) { ((UIControl *)v).enabled = YES; } // Dismiss the keyboard if ([v isKindOfClass:[UITextField class]]) { [(UITextField *)v resignFirstResponder]; } } return YES; } @end 

这是一个稍微强大的解决scheme,适用于iOS 7.它将recursion遍历search栏的所有子视图,以确保它启用所有UIControl (包括“取消”button)。

 - (void)enableControlsInView:(UIView *)view { for (id subview in view.subviews) { if ([subview isKindOfClass:[UIControl class]]) { [subview setEnabled:YES]; } [self enableControlsInView:subview]; } } 

在调用[self.searchBar resignFirstResponder]之后,请立即调用此方法:

 [self enableControlsInView:self.searchBar]; 

瞧! 取消button保持启用。

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

我发现一个不同的方法,使其在iOS 7中的工作。

我正在尝试的东西就像Twitter的iOS应用程序。 如果您单击“时间轴”选项卡中的放大镜,则显示UISearchBar ,同时激活“取消”button,显示键盘和最近的search屏幕。 滚动最近的search屏幕,它隐藏键盘,但它保持取消button激活。

这是我的工作代码:

 UIView *searchBarSubview = self.searchBar.subviews[0]; NSArray *subviewCache = [searchBarSubview valueForKeyPath:@"subviewCache"]; if ([subviewCache[2] respondsToSelector:@selector(setEnabled:)]) { [subviewCache[2] setValue:@YES forKeyPath:@"enabled"]; } 

我通过在我的表视图的scrollViewWillBeginDragging:设置一个断点来解决这个问题。 我看着我的UISearchBar ,露出它的子视图。 它总是只有一个,这是UIViewtypes(我的variablessearchBarSubview )。

在这里输入图像说明

然后,该UIView拥有一个名为subviewCache NSArray ,我注意到最后一个元素,这是第三个,是UINavigationButtontypes,不在公共API中。 所以我开始使用键值编码。 我检查了UINavigationButton是否响应了setEnabled: ,幸运的是,它的确如此。 所以我把属性设置为@YES 。 原来那个UINavigationButton 取消button。

如果苹果决定改变一个UISearchBar的内部的实现,这肯定会打破,但是到底是什么。 它现在工作。

David Douglas答复的SWIFT版本(在iOS9上testing)

 func enableSearchCancelButton(searchBar: UISearchBar){ for view in searchBar.subviews { for subview in view.subviews { if let button = subview as? UIButton { button.enabled = true } } } } 

build立在smileyborg的答案 ,只需将其放置在您的searchBar代表:

 - (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar { dispatch_async(dispatch_get_main_queue(), ^{ __block __weak void (^weakEnsureCancelButtonRemainsEnabled)(UIView *); void (^ensureCancelButtonRemainsEnabled)(UIView *); weakEnsureCancelButtonRemainsEnabled = ensureCancelButtonRemainsEnabled = ^(UIView *view) { for (UIView *subview in view.subviews) { if ([subview isKindOfClass:[UIControl class]]) { [(UIControl *)subview setEnabled:YES]; } weakEnsureCancelButtonRemainsEnabled(subview); } }; ensureCancelButtonRemainsEnabled(searchBar); }); } 

此解决scheme在iOS 7及更高版本上运行良好。

你可以创build从UISearchBarinheritance的CustomSearchBar并实现这个方法:

 - (void)layoutSubviews { [super layoutSubviews]; @try { UIView *baseView = self.subviews[0]; for (UIView *possibleButton in baseView.subviews) { if ([possibleButton respondsToSelector:@selector(setEnabled:)]) { [(UIControl *)possibleButton setEnabled:YES]; } } } @catch (NSException *exception) { NSLog(@"ERROR%@",exception); } } 

更好的解决scheme是

 [UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil].enabled = YES; 

对于iOS 10,Swift 3:

 for subView in self.movieSearchBar.subviews { for view in subView.subviews { if view.isKind(of:NSClassFromString("UIButton")!) { let cancelButton = view as! UIButton cancelButton.isEnabled = true } } } 

更好和简单的方法:

 [(UIButton *)[self.searchBar valueForKey:@"_cancelButton"] setEnabled:YES]; 

对于iOS 9/10(testing),Swift 3(更短):

 searchBar.subviews.flatMap({$0.subviews}).forEach({ ($0 as? UIButton)?.isEnabled = true })