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
,露出它的子视图。 它总是只有一个,这是UIView
types(我的variablessearchBarSubview
)。
然后,该UIView
拥有一个名为subviewCache
NSArray
,我注意到最后一个元素,这是第三个,是UINavigationButton
types,不在公共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 } } } }