ios UISearchController:即使搜索栏为空也显示结果

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30790244/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 06:22:34  来源:igfitidea点击:

UISearchController: show results even when search bar is empty

iosiphoneios8uisearchcontroller

提问by optimus

As I understand, the default behaviour of UISearchControlleris:

据我了解,的默认行为UISearchController是:

  1. On tapping search bar, background is dimmed and 'cancel' button is shown. SearchResultsControlleris not shown till this point.
  2. SearchResultsControlleris displayed only if search bar is not empty.
  1. 在点击搜索栏时,背景变暗并显示“取消”按钮。SearchResultsController直到此时才显示。
  2. SearchResultsController仅当搜索栏不为空时才显示。

I want to display SearchResultsControllereven when search bar is empty but selected (i.e is case 1 above).

SearchResultsController即使搜索栏为空但已选中(即上面的情况 1),我也想显示。

Simply put, instead of background dimming, I would like to show Search results.

简单地说,我想显示搜索结果,而不是背景变暗。

Is there a way for doing this?

有没有办法做到这一点?

More Clarification:

更多说明:

I am not using UISearchControllerto filter results shown on the view on which it is shown, but some other unrelated results. It will be like what facebook does on its 'News Feed'. Tapping on search bar shows search suggestions initially and then, when we start editing, it shows search results which might not be related to news feed.

我不是UISearchController用来过滤显示它的视图上显示的结果,而是一些其他不相关的结果。这将就像 facebook 在其“新闻提要”上所做的一样。点击搜索栏最初会显示搜索建议,然后当我们开始编辑时,它会显示可能与新闻提要无关的搜索结果。

采纳答案by optimus

If your searchBar is active but has no text, the underlying tableView results are shown. That's the built-in behavior, and the reason why searchResultsController is hidden for that state.

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

To change the behavior when search is active but not filtering, you're going to have to show the searchResultsController when it is normally still hidden.

要在搜索处于活动状态但未进行过滤时更改行为,您必须在它通常仍处于隐藏状态时显示 searchResultsController。

There may be a good way to accomplish this via <UISearchResultsUpdating>and updateSearchResultsForSearchController:. If you can solve it via the protocol, that's the preferred way to go.

可能有一个很好的方法可以通过<UISearchResultsUpdating>和来实现这一点updateSearchResultsForSearchController:。如果您可以通过协议解决它,那就是首选方式。

If that doesn't help, you're left with hacking the built-in behavior. I wouldn't recommend or rely on it, and it's going to be fragile, but here's an answer if you choose that option:

如果这没有帮助,您就只能破解内置行为了。我不会推荐或依赖它,它会很脆弱,但如果您选择该选项,这里有一个答案:

  1. Make sure your tableViewController conforms to <UISearchControllerDelegate>, and add

    self.searchController.delegate = self;

  2. Implement willPresentSearchController:

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

    This makes the searchResultsControllervisible after its UISearchControllerset it to hidden.

  3. Implement didPresentSearchController:

    - (void)didPresentSearchController:(UISearchController *)searchController
    {
        searchController.searchResultsController.view.hidden = NO;
    }
    
  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;
    }
    

For a better way to work around the built-in behavior, see malhal's answer.

有关解决内置行为的更好方法,请参阅malhal 的回答

回答by Ken Toh

You can simply implement the UISearchResultsUpdatingprotocol and set the results controller view to always show in updateSearchResultsForSearchController:

您可以简单地实现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
   ..
}

This works because the method is called even when the search bar is activated, without any text.

这是有效的,因为即使在激活搜索栏时也会调用该方法,没有任何文本。

回答by mashix

I have tried PetahChristian solution, the preload result did show up when we first focus the searchbar, but when we enter something then clear it, the preload results will not reappear.

我试过 PetahChristian 解决方案,当我们第一次聚焦搜索栏时,预加载结果确实出现了,但是当我们输入一些内容然后清除它时,预加载结果将不会重新出现。

I came up with another solution. We only need to add a delegate into SearchResultsController and call it when our searchController.searchBar.text is empty. Something like this:

我想出了另一个解决方案。我们只需要在 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()
        ...
    }
    ...
}

And in the controller contains the SearchController, we add our delegate:

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

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

回答by malhal

With tricky things like this I recommend the sledge hammer approach! That is to detect when something tries to make it hidden and when it does, change it back. This can be done via KVO (Key Value Observing). This will work no matter what, without having to handle all the intricacies of the search bar. Sorry the code is complicated but KVO is an older style API but my code follows recommend practice. In your SearchResultsViewController put this:

对于像这样棘手的事情,我推荐大锤方法!那就是检测什么时候有东西试图隐藏它,当它隐藏时,把它改回来。这可以通过 KVO(关键值观察)来完成。无论如何,这都可以工作,而无需处理搜索栏的所有复杂问题。抱歉,代码很复杂,但 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

This works in all cases including if the text is cleared.

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

Lastly, to prevent the table doing an ugly fade to grey then to white when the search activates, use this:

最后,为了防止表格在搜索激活时丑陋地淡化为灰色然后变为白色,请使用以下命令:

self.searchController.dimsBackgroundDuringPresentation = NO;

回答by Yafi

Swift 3 Version:

斯威夫特 3 版本:

If your searchResultControlleris not nil and you are using a separate table view controller to show the search results, then you can make that table view controller conform to UISearchResultUpdatingand in the updateSearchResultsfunction, you can simply unhide the view.

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

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

Swift 4 Version:

斯威夫特 4 版本:

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

回答by Simon Wang

Updated for iOS 13

针对 iOS 13 更新

From iOS13, we got system API support for this behaviour. You can set the property showsSearchResultsController = true

从 iOS13 开始,我们获得了对此行为的系统 API 支持。你可以设置属性showsSearchResultsController = true

WWDC screenshot

世界开发者大会截图

For iOS 12 and below

对于 iOS 12 及以下

I am recently working on UISearchController. I want to show search history in searchResultsControllerwhen search bar is empty. So searchResultsControllerneeds to show up whenever UISearchControllergets presented.

我最近在工作UISearchController。我想在searchResultsController搜索栏为空时显示搜索历史。因此searchResultsController,无论何时出现,都需要UISearchController出现。

Here, I use another solution to make the searchResultsControlleralways visible by overriding the hiddenproperty in a custom view.

在这里,我使用另一种解决方案searchResultsController通过覆盖hidden自定义视图中的属性来使始终可见。

for example, my searchResultsControlleris a UITableViewController. I create a VisibleTableViewas a subclass of UITableView, and then change the UITableViewcustom class of searchResultsControllerto VisibleTableViewin xib or storyboard. This way, my searchResultsControllerwill never be hidden by UISearchController.

例如,我的searchResultsController是一个UITableViewController. 我创建了一个VisibleTableView作为 的子类UITableView,然后在 xib 或故事板中将的UITableView自定义类更改searchResultsControllerVisibleTableView。这样,我的searchResultsController永远不会被隐藏UISearchController

The good things here:

这里的好东西:

  1. Easier to implement than KVO.

  2. No delay to show searchResultsController. Flipping the hidden flag in "updateSearchResults" delegate method works, but there is a delay to show the searchResultsController.

  3. It does't reset the hidden flag, so there is no UI gap/jumping between hidden and visible.

  1. 比 KVO 更容易实现。

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

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

Swift 3 sample code:

Swift 3 示例代码

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

回答by matt

What is being hidden is the search results controller's view. Therefore it is sufficient to unhide it any time it might be hidden. Simply do as follows in the search results controller:

隐藏的是搜索结果控制器的视图。因此,在它可能被隐藏的任何时候取消隐藏它就足够了。只需在搜索结果控制器中执行以下操作:

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 ...
}

Now the results view (i.e. the table view) is always visible, even when the search bar text is empty.

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

By the way, the iOS Mail app behaves like this, and I assume that's how it's implemented (unless Apple has access to some secret private UISearchController setting).

顺便说一下,iOS 邮件应用程序的行为是这样的,我假设它是这样实现的(除非 Apple 可以访问一些秘密的私有 UISearchController 设置)。

[Tested in iOS 10 and iOS 11; I didn't test on any earlier system.]

[在 iOS 10 和 iOS 11 中测试;我没有在任何早期的系统上进行测试。]

回答by Niels

The Swift 2.3 version of @malhal's approach:

@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)
        }
    }
}

回答by Praveen Gowda I V

If you don't want to dim the results, set the dimsBackgroundDuringPresentationproperty to false.

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

This will make sure that the underlying content is not dimmed during a search.

这将确保基础内容在搜索过程中不会变暗。

You will also have to make sure you return results even when the searchText is empty otherwise an empty tableview will be displayed.

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

回答by skensell

I spent a lot of time with this, and ultimately the solution I went with is like @malhals's, but the amount of code is significantly reduced by using facebook's KVOController: https://github.com/facebook/KVOController. Another advantage here is that if your searchResultsController is a UINavigationControllerthen you don't need to subclass it just to add @malhal's code.

我花了很多时间,最终我采用的解决方案类似于@malhals 的解决方案,但通过使用 facebook 的 KVOController: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;