iOS8无法在UISearchController的search栏上隐藏取消button

我的目标是防止取消button出现在UISearchController的search栏中。 我使用UISearchController示例代码从Apple的Table Search开始,并隐藏了取消button,如下面的代码片段所示。 但是,当用户点击文本字段时,取消button仍然出现。 任何帮助?

override func viewDidLoad() { super.viewDidLoad() resultsTableController = ResultsTableController() searchController = UISearchController(searchResultsController: resultsTableController) searchController.searchResultsUpdater = self searchController.searchBar.sizeToFit() tableView.tableHeaderView = searchController.searchBar searchController.searchBar.delegate = self //Hide cancel button - added by me searchController.searchBar.showsCancelButton = false ... 

我认为有三种方法可以达到这个目的:

  1. 重写searchDisplayControllerDidBeginSearch并使用以下代码:

searchController.searchBar.showsCancelButton = false

  1. 子类UISearchBar并覆盖layoutSubviews以在系统尝试绘制该variables时更改该variables。

  2. 注册键盘通知UIKeyboardWillShowNotification并应用第1点中的代码

当然可以随时执行您的search栏。

对于iOS 8和UISearchController,请使用UISearchControllerDelegate中的此委托方法:

 func didPresentSearchController(searchController: UISearchController) { searchController.searchBar.showsCancelButton = false } 

不要忘记将自己设置为委托: searchController.delegate = self

简单的子类UISearchControllerUISearchBar

 class NoCancelButtonSearchController: UISearchController { let noCancelButtonSearchBar = NoCancelButtonSearchBar() override var searchBar: UISearchBar { return noCancelButtonSearchBar } } class NoCancelButtonSearchBar: UISearchBar { override func setShowsCancelButton(_ showsCancelButton: Bool, animated: Bool) { /* void */ } } 

下面的github项目子类UISearchBar作为解决scheme2提供:

https://github.com/mechaman/CustomSearchControllerSwift

最重要的是,它也是UISearchController的子类,使其能够将search栏放在tableView标题以外的地方!

希望这可以帮助。

TL; DR :inheritanceUISearchBar并覆盖setShowsCancelButton:setShowsCancelButton:animated:隐藏取消button。

如果search栏不是第一个响应者(键盘未激活并显示),我将其设置为NO ,因为这实际上是取消命令。

FJSearchBar

标记searchController.searchBar.showsCancelButton = NO似乎不适用于iOS 8 。 我还没有testingiOS 9

FJSearchBar.h

空了,但为了完整而放置在这里。

 @import UIKit; @interface FJSearchBar : UISearchBar @end 

FJSearchBar.m

 #import "FJSearchBar.h" @implementation FJSearchBar - (void)setShowsCancelButton:(BOOL)showsCancelButton { // do nothing } - (void)setShowsCancelButton:(BOOL)showsCancelButton animated:(BOOL)animated { // do nothing } @end 

FJSearchController

这是你想要做出真正改变的地方。 我将UISearchBarDelegate分成它自己的类别,因为,恕我直言,类别使类更清洁,更容易维护。 如果你想把委托保存在主类的接口/实现中,那么欢迎你这样做。

FJSearchController.h

 @import UIKit; @interface FJSearchController : UISearchController @end @interface FJSearchController (UISearchBarDelegate) <UISearchBarDelegate> @end 

FJSearchController.m

 #import "FJSearchController.h" #import "FJSearchBar.h" @implementation FJSearchController { @private FJSearchBar *_searchBar; BOOL _clearedOutside; } - (UISearchBar *)searchBar { if (_searchBar == nil) { // if you're not hiding the cancel button, simply uncomment the line below and delete the FJSearchBar alloc/init // _searchBar = [[UISearchBar alloc] init]; _searchBar = [[FJSearchBar alloc] init]; _searchBar.delegate = self; } return _searchBar; } @end @implementation FJSearchController (UISearchBarDelegate) - (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar { // if we cleared from outside then we should not allow any new editing BOOL shouldAllowEditing = !_clearedOutside; _clearedOutside = NO; return shouldAllowEditing; } - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { // hide the keyboard since the user will no longer add any more input [searchBar resignFirstResponder]; } - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { if (![searchBar isFirstResponder]) { // the user cleared the search while not in typing mode, so we should deactivate searching self.active = NO; _clearedOutside = YES; return; } // update the search results [self.searchResultsUpdater updateSearchResultsForSearchController:self]; } @end 

有些部分要注意:

  1. 我已经把search栏和BOOL作为私有variables,而不是属性,因为
    • 他们比私有财产更轻量。
    • 他们不需要被外界看到或修改。
  2. 我们检查searchBar是否是第一个响应者。 如果不是,那么我们实际上停用search控制器,因为文本是空的,我们不再search。 如果你真的想确定,你也可以确保searchText.length == 0
  3. searchBar:textDidChange:searchBarShouldBeginEditing:之前被调用,这就是为什么我们按这个顺序处理它的原因。
  4. 我每次更新文本都会更新search结果,但是您可能需要移动[self.searchResultsUpdater updateSearchResultsForSearchController:self]; searchBarSearchButtonClicked:如果您只想在用户按下searchbutton后执行search

这是我能在Swift中想到的最简单的解决scheme。

自定义search控制器

 class CustomSearchController: UISearchController { var _searchBar: CustomSearchBar override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { self._searchBar = CustomSearchBar() super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) } override init(searchResultsController: UIViewController?) { self._searchBar = CustomSearchBar() super.init(searchResultsController: searchResultsController) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override var searchBar: UISearchBar { return self._searchBar } } 

自定义search栏:

 class CustomSearchBar: UISearchBar { override func setShowsCancelButton(showsCancelButton: Bool, animated: Bool) { // do nothing } } 

其中最重要的部分是只在init创build_searchBar对象,而不是在存储属性中创build它。

使用UISearchControllerDelegate。

 func willPresentSearchController(_ searchController: UISearchController) { searchController.searchBar.setValue("", forKey:"_cancelButtonText") } 

只是你的UISearchController子类,并执行以下操作:

 class CustomSearchController: UISearchController { override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() searchBar.showsCancelButton = false } } 

这是我想出的最简单的解决scheme,以解决闪烁的取消button问题。