UISearchBar禁用取消button的自动禁用

我已经实现了一个UISearchBar到一个表视图,几乎所有的东西都在工作,除了一件小事情:当我input文本,然后按键盘上的searchbutton,键盘消失,search结果是唯一的项目在表中显示,文本保留在UISearchBar中,但取消button被禁用。

我一直试图让我的列表接近苹果通讯录应用程序的function,当你按下search应用程序,它不会禁用取消button。

当我查看UISearchBar头文件时,我注意到了_searchBarFlags结构下的autoDisableCancelButton标志,但它是私有的。

当我设置UISearchBar时,有什么东西是我想念的吗?

我find了解决scheme。 您可以使用此for-loop循环search栏的子视图,并在键盘上按下searchbutton时启用它。

for (UIView *possibleButton in searchBar.subviews) { if ([possibleButton isKindOfClass:[UIButton class]]) { UIButton *cancelButton = (UIButton*)possibleButton; cancelButton.enabled = YES; break; } } 

我不得不调整这一点,让它在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; } } } } 

有两种方法可以轻松实现

 - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{ // The small and dirty [(UIButton*)[searchBar valueForKey:@"_cancelButton"] setEnabled:YES]; // The long and safe UIButton *cancelButton = [searchBar valueForKey:@"_cancelButton"]; if ([cancelButton respondsToSelector:@selector(setEnabled:)]) { cancelButton.enabled = YES; } } 

你应该跟第二个一样,如果苹果公司在后台改变它,它不会崩溃你的应用程序。

顺便说一句,我testing从iOS 4.0到8.2,没有任何改变,我也用我的商店批准的应用程序没有任何问题。

这是什么使它在iOS 6上工作:

 searchBar.showsCancelButton = YES; searchBar.showsScopeBar = YES; [searchBar sizeToFit]; [searchBar setShowsCancelButton:YES animated:YES]; 

这是我的解决scheme,适用于所有iOS版本的所有情况。

IE浏览器,其他解决scheme不能处理,因为用户拖动滚动视图键盘被解散。

 - (void)enableCancelButton:(UIView *)view { if ([view isKindOfClass:[UIButton class]]) { [(UIButton *)view setEnabled:YES]; } else { for (UIView *subview in view.subviews) { [self enableCancelButton:subview]; } } } // This will handle whenever the text field is resigned non-programatically // (IE, because it's set to resign when the scroll view is dragged in your storyboard.) - (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar { [self performSelector:@selector(enableCancelButton:) withObject:searchBar afterDelay:0.001]; } // Also follow up every [searchBar resignFirstResponder]; // with [self enableCancelButton:searchBar]; 

没有答案为我工作。 我的目标是iOS 7,但我find了答案。

我正在尝试的东西就像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的内部的实现,这肯定会打破,但是到底是什么。 它现在工作。

根据我的答案在这里 ,把这个在你的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); }); } 

对于Monotouch或Xamarin iOS,我有以下适用于iOS 7和iOS 8的C#解决scheme:

 foreach(UIView view in searchBar.Subviews) { foreach(var subview in view.Subviews) { //Console.WriteLine(subview.GetType()); if(subview.GetType() == typeof(UIButton)) { if(subview.RespondsToSelector(new Selector("setEnabled:"))) { UIButton cancelButton = (UIButton)subview; cancelButton.Enabled = true; Console.WriteLine("enabledCancelButton"); return; } } } } 

这个答案是基于David Douglas的解决scheme。

更完整的答案:

  • 自iOS 7以来,在searchBar下还有一个额外的子视图级别
  • searchBarTextDidEndEditing是一个启用取消button的好地方

 extension MyController: UISearchBarDelegate { public func searchBarTextDidEndEditing(_ searchBar: UISearchBar) { DispatchQueue.main.async { // you need that since the disabling will // happen after searchBarTextDidEndEditing is called searchBar.subviews.forEach({ view in view.subviews.forEach({ subview in // ios 7+ if let cancelButton = subview as? UIButton { cancelButton.isEnabled = true cancelButton.isUserInteractionEnabled = true return } }) // ios 7- if let cancelButton = subview as? UIButton { cancelButton.isEnabled = true cancelButton.isUserInteractionEnabled = true return } }) } } } 

下面是一个Swift 3解决scheme,它使用扩展来轻松获取取消button:

 extension UISearchBar { var cancelButton: UIButton? { for subView1 in subviews { for subView2 in subView1.subviews { if let cancelButton = subView2 as? UIButton { return cancelButton } } } return nil } } 

现在用于:

 class MyTableViewController : UITableViewController, UISearchBarDelegate { var searchBar = UISearchBar() func viewDidLoad() { super.viewDidLoad() searchBar.delegate = self tableView.tableHeaderView = searchBar } func searchBarTextDidEndEditing(_ searchBar: UISearchBar) { DispatchQueue.main.async { if let cancelButton = searchBar.cancelButton { cancelButton.isEnabled = true cancelButton.isUserInteractionEnabled = true } } } }