12

我有一个带有搜索栏的非 tableview 视图,虽然它工作得很好,但当搜索栏中有一个空字符串时,搜索显示控制器隐藏了 table 视图并覆盖了一个暗色的视图。我希望它在搜索栏中显示空字符串时显示预加载的数据,而不是隐藏表格视图并覆盖搜索栏下方的暗色视图。就像 iOS 版 Safari 中的 Google 搜索栏的工作方式一样。

我之前在 stackoverflow 上发现了一个类似的问题: UISearchDisplayController - how to preload searchResultTableView,我真的无法让它工作。

获取预加载数据并将当前数据设置为它没有问题,但我不确定如何防止显示控制器删除 searchResultsTableView。

提前致谢。

4

7 回答 7

13

我终于找到了一种方法来做到这一点。

我发现 searchDisplayController 只是从超级视图中删除了 searchResultsTableView,所以每当显示控制器试图隐藏表格视图时,我只是将表格视图添加回超级视图:

- (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView
{
    // add the tableview back in
    [self.view addSubview:self.searchDisplayController.searchResultsTableView];
}

然后我还必须在第一次单击搜索栏时显示 tableview,所以我做了:

- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
{
    // after the data has been preloaded
    self.searchResults = self.allItems;
    [self.searchDisplayController.searchResultsTableView reloadData];
}

- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller
{
    [self.view addSubview:self.searchDisplayController.searchResultsTableView];
}

对我来说,“allItems”是我存储所有可搜索项目的地方,“searchResults”是存储过滤项目(搜索后)的地方。当然,您必须在重新加载数据之前预加载项目(例如搜索历史)。

我不知道这在性能方面是否是一种好方法,但它对我来说非常有效,我希望这对其他人也有用。如果有更好的方法可以做到这一点,请发表评论。

于 2012-05-28T04:43:14.073 回答
4

经过几个小时后,我终于找到了适用于 iOS 7 的解决方案

只需在您的 UISearchDisplayDelegate 中实现以下两个方法

-(void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView {

    // We need to prevent the resultsTable from hiding if the search is still active
    if (self.searchDisplayController.active == YES) {
        tableView.hidden = NO;
    }
}

当搜索开始时,searchResultsTableView 被自动隐藏了,所以我们需要再次取消隐藏

- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {

    controller.searchResultsTableView.hidden = NO;

    // Then we need to remove the semi transparent overlay which is here
    for (UIView *v in [[[controller.searchResultsTableView superview] superview] subviews]) {

        if (v.frame.origin.y == 64) {
            [v setHidden:YES];
        }
    }

}
于 2014-02-16T23:24:14.890 回答
4

我为这个问题找到了一个更好的解决方案,它似乎在 iOS 6 和 7 上完美运行。虽然它仍然是一个 hack,但它比上面的更清洁和面向未来的 hack。其他解决方案无法始终如一地工作,并阻止某些 UISearchDisplayDelegate 方法触发!此外,我遇到了复杂的嵌入问题,我无法用上述方法解决。其他解决方案的主要问题是它们严重混淆了 UISearchDisplayController 的内部结构。我的解决方案是基于观察 UISearchDisplayContoller 是 UISearchbarDelegate 并且可以通过模拟搜索字段中的按键来触发结果表的自动取消调暗和显示!所以:

- (void) searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller 
{
    if ([controller respondsToSelector: @selector(searchBar:textDidChange:)])
        [(id<UISearchBarDelegate>)controller searchBar: controller.searchBar textDidChange: @" "];
}

这段代码通过检查它是否响应 UISearchbarDelegate 方法来防止崩溃,并发送空格 @" " 来欺骗 UISearchDisplayController 认为用户输入了一个字母,从而防止崩溃。

现在,如果用户键入内容然后将其删除,表格将再次变暗。其他解决方案尝试通过在 searchDisplayController:didHideSearchResultsTableView: 方法中执行某些操作来解决此问题。但这对我来说没有意义,因为当您取消搜索时,它肯定需要真正隐藏您的结果表,并且在这种情况下您可能需要运行代码。我对此部分的解决方案是子类化(请注意,如果您的项目需要,您可以使用 Method Swizzled Category 使其在任何地方都可以工作):

// privately declare protocol to suppress compiler warning
@interface UISearchDisplayController (Super) <UISearchBarDelegate>
@end

// subclass to change behavior
@interface GMSearchDisplayController : UISearchDisplayController
@end

@implementation GMSearchDisplayController

- (void) searchBar: (UISearchBar *) searchBar textDidChange: (NSString *) searchString
{
    if (searchString.length == 0)
        searchString = @" ";
    if ([super respondsToSelector: @selector(searchBar:textDidChange:)])
        [super searchBar: searchBar textDidChange: searchString];
}

@end

此代码通过拦截 textDidChange 委托方法并将 nil 或空字符串更改为空格字符串 @" " 来防止在空搜索栏上发生的正常隐藏/变暗。如果您正在使用第二位代码,那么您可以修改第一位以传递 nil 而不是 @" ",因为第二位将为您进行所需的转换为 @" "。

在我自己的项目中,我需要处理用户输入空格的情况,所以我使用了一个定义的标记,而不是上面的 @" ":

// arbitrary token used internally
#define SEARCH_PRELOAD_CONDITIONAL @"_#preresults#_"

然后通过将其转换回 nil 字符串在内部处理它:

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    if ([searchString isEqualToString: SEARCH_PRELOAD_CONDITIONAL])
        searchString = nil;
}

享受!:)

于 2014-07-17T12:05:54.233 回答
2

这适用于 iOS 8:

- (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView
{
  self.searchDisplayController.searchResultsTableView.hidden = NO;
}

- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller
{
    self.searchDisplayController.searchResultsTableView.hidden = NO;
    [self.searchDisplayController.searchResultsTableView.superview.superview bringSubviewToFront:self.searchDisplayController.searchResultsTableView.superview];

    CGRect frame = self.searchDisplayController.searchResultsTableView.frame;
    self.searchDisplayController.searchResultsTableView.frame = CGRectMake(frame.origin.x, 64, frame.size.width, frame.size.height);
}
于 2015-01-07T02:18:37.523 回答
1

当您开始搜索时,会调用此方法。添加 searchResultsTableView 并取消隐藏它。然后它将显示您已经预加载的数据。我必须预先加载您的数据才能使其正常工作。

- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller
{
    CGRect testFrame = CGRectMake(0, self.notesSearchBar.frame.size.height, self.notesSearchBar.frame.size.width, self.view.frame.size.height - self.notesSearchBar.frame.size.height);
    self.searchDisplayController.searchResultsTableView.frame = testFrame;
    [self.notesSearchBar.superview addSubview:self.searchDisplayController.searchResultsTableView];

//    [self.view addSubview:self.searchDisplayController.searchResultsTableView];
    controller.searchResultsTableView.hidden = NO;
}

-(void) searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView
{
    CGRect testFrame = CGRectMake(0, self.notesSearchBar.frame.size.height, self.notesSearchBar.frame.size.width, self.view.frame.size.height - self.notesSearchBar.frame.size.height);
    self.searchDisplayController.searchResultsTableView.frame = testFrame;
    [self.notesSearchBar.superview addSubview:self.searchDisplayController.searchResultsTableView];

    //    [self.view addSubview:self.searchDisplayController.searchResultsTableView];
    controller.searchResultsTableView.hidden = NO;
}


-(void) searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
{
    controller.searchResultsTableView.hidden = YES;
}
于 2013-10-30T02:22:09.910 回答
1

iOS 9 工作代码。

- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
    // Bring the search table view to the view's front
    self.searchDisplayController.searchResultsTableView.hidden = NO;
    [self.searchDisplayController.searchResultsTableView.superview bringSubviewToFront:self.searchDisplayController.searchResultsTableView];
}

- (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView {
    // We need to prevent the resultsTable from hiding if the search is still active
    if (self.searchDisplayController.active == YES) {
        tableView.hidden = NO;
    }
}
于 2016-01-07T14:24:07.073 回答
0

斯威夫特 2.0+ 版本

func searchDisplayControllerDidBeginSearch(controller: UISearchDisplayController) {
    controller.searchResultsTableView.hidden = false
    controller.searchResultsTableView.superview!.bringSubviewToFront(controller.searchResultsTableView)
}

func searchDisplayController(controller: UISearchDisplayController, didHideSearchResultsTableView tableView: UITableView) {
    if ((searchDisplayController?.active) != nil) {
        tableView.hidden = false
    }
}
于 2016-03-09T15:12:50.660 回答