UISearchController:即使在search栏为空时也显示结果

据我所知, UISearchController的默认行为是:

  1. 点击search栏时,背景变暗,显示“取消”button。 SearchResultsController直到此时才显示。
  2. SearchResultsController仅在search栏不为空时显示。

即使search栏是空的,但select了(即上面的情况1),我也想显示SearchResultsController

简而言之,我想显示search结果,而不是背景调暗。

有没有办法做到这一点?

更多的澄清:

我没有使用UISearchController过滤显示在其上的视图显示的结果,但一些其他无关的结果。 这将是像Facebook的“新闻”。 点击search栏会显示searchbuild议,然后在开始编辑时显示可能与新闻Feed无关的search结果。

如果您的searchBar处于活动状态,但没有文本,则会显示基础的tableView结果。 这是内置的行为,以及为什么searchResultsController隐藏该状态的原因。

要在search处于活动状态但不进行过滤时更改行为,则必须在正常情况下仍然隐藏时显示searchResultsController。

通过<UISearchResultsUpdating>updateSearchResultsForSearchController:可能有一个很好的方法。 如果你可以通过协议解决它,这是首选的方法。

如果这样做没有帮助,那就留下黑客的内置行为。 我不会推荐或依赖它,而且会变得脆弱,但是如果你select这个选项,这是一个答案:

  1. 确保你的tableViewController符合<UISearchControllerDelegate> ,然后添加

    self.searchController.delegate = self;

  2. 实现willPresentSearchController:

     - (void)willPresentSearchController:(UISearchController *)searchController { dispatch_async(dispatch_get_main_queue(), ^{ searchController.searchResultsController.view.hidden = NO; }); } 

    这会使searchResultsController在其UISearchController设置为隐藏后可见。

  3. 实现didPresentSearchController:

     - (void)didPresentSearchController:(UISearchController *)searchController { searchController.searchResultsController.view.hidden = NO; } 

为了更好地解决内置行为,请参阅malhal的答案 。

您可以简单地实现UISearchResultsUpdating协议,并将结果控制器视图设置为始终显示在updateSearchResultsForSearchController

  func updateSearchResultsForSearchController(searchController: UISearchController) { // Always show the search result controller searchController.searchResultsController?.view.hidden = false // Update your search results data and reload data .. } 

这是有效的,因为即使当search栏被激活时,该方法也被调用,没有任何文本。

我已经尝试了PetahChristian解决scheme,当我们第一次关注search栏时,预载结果显示出来,但是当我们input一些内容然后清除它时,预载结果不会再出现。

我想出了另一个解决scheme。 我们只需要将一个委托添加到SearchResultsController中,并在我们的searchController.searchBar.text为空时调用它。 像这样的东西:

SearchResultsController:

 protocol SearchResultsViewControllerDelegate { func reassureShowingList() -> Void } class FullSearchResultsViewController: UIViewController, UISearchResultsUpdating{ var delegate: SearchResultsViewControllerDelegate? ... func updateSearchResultsForSearchController(searchController: UISearchController) { let query = searchController.searchBar.text?.trim() if query == nil || query!.isEmpty { ... self.delegate?.reassureShowingList() ... } ... } 

在控制器中包含SearchController,我们添加我们的委托:

 self.searchResultsController.delegate = self func reassureShowingList() { searchController.searchResultsController!.view.hidden = false } 

像这样棘手的事情,我build议大锤的做法! 那就是要检测什么时候什么东西试图让它隐藏起来,什么时候把它改回来。 这可以通过KVO(关键值观察)完成。 无论如何,这将无需处理search栏的所有复杂问题。 对不起,代码是复杂的,但KVO是一个老式的API,但我的代码遵循推荐的做法。 在您的SearchResultsViewController把这个:

 static int kHidden; @implementation SearchResultsViewController -(void)viewDidLoad{ [super viewDidLoad]; [self.view addObserver:self forKeyPath:@"hidden" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:&kHidden]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { // if it was our observation if(context == &kHidden){ // if the view is hidden then make it visible. if([[change objectForKey:NSKeyValueChangeNewKey] boolValue]){ self.view.hidden = NO; } } else{ // if necessary, pass the method up the subclass hierarchy. if([super respondsToSelector:@selector(observeValueForKeyPath:ofObject:change:context:)]){ [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } } - (void)dealloc { [self.view removeObserver:self forKeyPath:@"hidden"]; } // Here have the rest of your code for the search results table. @end 

这适用于所有情况,包括文本是否被清除。

最后,为了防止表格在search激活时变成灰色,然后变成白色,请使用以下命令:

 self.searchController.dimsBackgroundDuringPresentation = NO; 

Swift 3版本:

如果您的searchResultController不是零,而您使用单独的表视图控制器来显示search结果,那么您可以使该表视图控制器符合UISearchResultUpdating并在updateSearchResults函数中,您可以简单地取消隐藏视图。

 func updateSearchResults(for searchController: UISearchController) { view.hidden = false } 

@ malhal的方法的Swift 2.3版本:

 class SearchResultsViewController : UIViewController { var context = 0 override func viewDidLoad() { super.viewDidLoad() // Add observer view.addObserver(self, forKeyPath: "hidden", options: [ .New, .Old ], context: &context) } deinit { view.removeObserver(self, forKeyPath: "hidden") } override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) { if context == &self.context { if change?[NSKeyValueChangeNewKey] as? Bool == true { view.hidden = false } } else { super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context) } } } 

如果您不想调暗结果,请将dimsBackgroundDuringPresentation属性设置为false

这将确保在search期间底层内容不会变暗。

即使当searchText为空时,您也必须确保返回结果,否则将显示空的tableview。

search结果控制器的视图隐藏着什么。 因此,只要隐藏它就可以取消隐藏。 只需在search结果控制器中执行以下操作:

 override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.view.isHidden = false } func updateSearchResults(for searchController: UISearchController) { self.view.isHidden = false // ... your other code goes here ... } 

现在,结果视图(即表视图)始终可见,即使search栏文本为空。

顺便说一下,iOS邮件应用程序的行为就像这样,我假设它是如何实现的(除非苹果有权访问一些秘密的私有UISearchController设置)。

[在iOS 10和iOS 11中testing; 我没有在任何早期的系统上testing过。]

我最近在UISearchController上工作。 当search栏为空时,我想在searchResultsController中显示search历史logging。 所以当显示UISearchController时,需要显示searchResultsController。

我对翻转UISearchController设置的隐藏标志(内置行为)的解决scheme并不满意。 我已经尝试了另一个解决scheme,通过重写隐藏的属性在自定义视图中始终使searchResultsController可见。

例如,我的s​​earchResultsController是一个UITableViewController。 我创build一个VisibleTableView作为UITableView的一个子类,然后在xib或storyboard中将UITableView自定义的searchResultsController类更改为VisibleTableView。 这样,我的searchResultsController将永远不会被UISearchController隐藏。

这里的好东西:

  1. 比KVO更容易实施。

  2. 没有延迟显示searchResultsController。 在“updateSearchResults”委托方法中翻转隐藏的标志,但是显示searchResultsController有延迟。

  3. 它不会重置隐藏标志,所以在隐藏和可见之间没有UI间隙/跳跃。

Swift 3示例代码

 class VisibleTableView: UITableView { override var isHidden: Bool { get { return false } set { // ignoring any settings } } } 

我想你错了。

SearchResultsController只有在有结果时才会出现。 这与你的解释稍有不同。

结果将根据search栏中的文本手动加载。 所以如果search栏是空的,你可以拦截它,并返回你自己的结果集。

我花了很多时间,最终我使用的解决scheme就像@ malhals,但通过使用Facebook的KVOController,代码的数量显着减less: https : //github.com/facebook/KVOController 。 这里的另一个好处是,如果你的searchResultsController是一个UINavigationController那么你不需要为它添加子类就可以添加@ malhal的代码。

 // always show searchResultsController, even if text is empty [self.KVOController observe:self.searchController.searchResultsController.view keyPath:@"hidden" options:NSKeyValueObservingOptionNew block:^(id observer, UIView* view, NSDictionary *change) { if ([change[NSKeyValueChangeNewKey] boolValue] == YES) { view.hidden = NO; } }]; self.searchController.dimsBackgroundDuringPresentation = NO; 

最简单的方法是使用ReactiveCocoa这个扩展https://github.com/ColinEberhardt/ReactiveTwitterSearch/blob/master/ReactiveTwitterSearch/Util/UIKitExtensions.swift

  presentViewController(sc, animated: true, completion: { sc.searchResultsController?.view.rac_hidden.modify({ value -> Bool in return false }) } ) 

sc是你的UISearchController

我真的很喜欢Simon Wang的答案,并且与之合作,这就是我所做的,并且完美地工作:

我在我的自定义类中inheritanceUISearchController:

 class CustomClass: UISearchController { override var searchResultsController: UIViewController? { get { let viewController = super.searchResultsController viewController?.view.isHidden = false return viewController } set { // nothing } } } 

还要确保你没有在你的代码中的任何地方:

 self.resultsSearchController.isActive = true 

resultsSearchController是我的UISearchController

斯威夫特4版的马耳他回答 :

 class SearchController: UISearchController { private var viewIsHiddenObserver: NSKeyValueObservation? override func viewDidLoad() { super.viewDidLoad() viewIsHiddenObserver = self.searchResultsController?.view.observe(\.hidden, changeHandler: { [weak self] (view, _) in guard let searchController = self else {return} if view.isHidden && searchController.searchBar.isFirstResponder { view.isHidden = false } }) } } 

请注意[weak self] 。 否则,你会引入一个保留周期。