没有结果的UISearchDisplayController怎样使用tableView?

41
通常情况下,激活UISearchDisplayController时,会使tableView变暗并聚焦于searchBar。当您在searchBar中输入文本时,它会创建一个searchResultsTableView,并显示在searchBar和键盘之间。第二个UITableView加载/显示/隐藏/卸载时,将调用searchDisplayController的委托。通常,在输入时,它会显示实时搜索结果或自动完成条目。
在我的应用程序中,我想搜索Web服务,而且我不想为用户输入的每个字母调用Web服务。因此,我想完全禁用searchResultsTableView,并在用户输入文本时保留黑色遮罩。然后,一旦用户点击搜索按钮,我会触发搜索(带有加载屏幕)。
仅返回零行以供searchResultsTableView使用看起来不好,因为它会显示一个空的searchResultsTableView,并显示“没有结果”的消息。我尝试在出现表格时隐藏它(searchDisplayController:didLoadSearchResultsTableView:),这可以工作,但是黑暗的遮罩也被隐藏了,导致底层tableView完全可见。
除了从头开始重新创建UISearchDisplayController功能,还有什么想法吗?
10个回答

38

我刚刚想出了一个小技巧,而且在编辑搜索字符串时必须返回0个结果

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    savedSearchTerm = searchString;

    [controller.searchResultsTableView setBackgroundColor:[UIColor colorWithWhite:0.0 alpha:0.8]];
    [controller.searchResultsTableView setRowHeight:800];
    [controller.searchResultsTableView setScrollEnabled:NO];
    return NO;
}

- (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView
{
    // undo the changes above to prevent artefacts reported below by mclin
}

我认为你会想出接下来该做什么。


1
对我来说第一次就可以工作,但如果你搜索,点击x清除然后输入更多文本,它会显示所有带不透明黑色背景和白色分隔线的行。我猜这可能是UITableCellViews的问题,所以我将以下内容添加到您的函数中,它可以解决问题:for (UIView *subview in self.searchDisplayController.searchResultsTableView.subviews) { [subview removeFromSuperview];} - mclin
2
还值得在那里加入 'controller.searchResultsTableView.scrollEnabled = NO;' - Chris
太棒了的解决方案。并请给@Chris点个赞。为什么苹果不把这个作为一个可以选择的设置,这似乎真的很愚蠢,因为这正是地图应用程序的工作方式。 - jowie
需要记住的几点是:**(1)** 点击此表不会导致UISearchDisplayController被解除(我必须使用UITapGestureRecognizer)。 (2) 在iPad上,背景颜色的alpha值应该为~0.5。 - Frantic
我尝试过这个,但遇到了一些问题。我通常觉得Barry的方法更优雅,因为它使用了现有的结果表视图。 - Besi
使用 alpha 0.4 可使 iOS7 上的色调看起来完全相同。 - neilb

19

你尝试过这个吗:

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_lookup:) object:nil];
[self performSelector:@selector(_lookup:) withObject:txt afterDelay:0.20];

这样,如果用户在1/5秒内输入另一个字符,你只会进行一次网络调用。


1
使用object:nil,cancel调用是否会匹配?如果没有其他执行请求,最好调用普通的[NSObject cancelPreviousPerformRequestsWithTarget:self]。 - Thom

9

最终以上所述的方法似乎都不太有效,因此我想到了以下方法(当您准备好显示结果时,请调用removeTableHeader函数):

- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
    [self setTableHeader];
}

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
    [self setTableHeader];
}

- (void)setTableHeader {
    UIView *headerView = [[UIView alloc] initWithFrame:self.searchDisplayController.searchResultsTableView.frame];
    headerView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.8];

    [self.searchDisplayController.searchResultsTableView setBackgroundColor:[UIColor clearColor]];
    [self.searchDisplayController.searchResultsTableView setScrollEnabled:NO];
    [self.searchDisplayController.searchResultsTableView setTableHeaderView:headerView];

    [headerView release];
}

- (void)removeTableHeader {
    [self.searchDisplayController.searchResultsTableView setBackgroundColor:[UIColor whiteColor]];
    [self.searchDisplayController.searchResultsTableView setScrollEnabled:YES];
    [self.searchDisplayController.searchResultsTableView setTableHeaderView:nil];
}

显然,它使表格透明,添加了一个与表格大小相同的黑色/半透明表头,并禁用了表格上下滚动,因此您无法超过或越过表头。作为奖励,您可以在标题视图中添加一些内容(“请稍等…”或活动指示器)。

2
这种方法有点可行,但是你不能点击标题来关闭。 - ultravelocity
这个解决方案是我找到的最干净和最有效的。其他解决方案的主要问题在于,当“假”阴影叠加层可见并且您关闭搜索界面时,iOS会强制tableView变为不透明,并且屏幕会快速闪白,这很丑陋。但是这种实现不会发生这种情况。如果你想模仿默认的点击消失行为,只需向headerView添加UITapGestureRecognizer并在回调中调用searchDisplayController的setActive:animated:即可。 - Jeff Mascia
这只是一条与样式相关的备注。在这种情况下,您可能希望使用 showTableHeader 而不是 setTableHeader,因为它不是一个真正的设置器。 - Besi
+1 这是我个人认为最优雅的解决方案。为了修复 @chaiwalla 的评论,我在 HeaderView 中使用了一个 UIButton,并在 IBAction 中调用 [searchDisplayController setActive:NO],从而在触摸此区域时关闭搜索。 - Besi

9

我曾经遇到了和你一样的问题,我通过以下两个步骤解决了它:a)在开始搜索时将searchResultsTableView的alpha值设置为0,b)向viewController的视图中添加/删除overlayView。这对我来说非常有效。

@interface MyViewController()
//...
@property(nonatomic, retain) UIView *overlayView;
//...
@end

@implementation MyViewController
@synthesize overlayView = _overlayView;

//...

- (void)viewDidLoad
{
    //...

    //define your overlayView
    _overlayView = [[UIView alloc] initWithFrame:CGRectMake(0, 44, 320, 480)];
    _overlayView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.8];
}

//hide the searchResultsTableView
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
{
    self.searchDisplayController.searchResultsTableView.alpha = 0.0f;
}

//when ending the search, hide the overlayView
- (void) searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
{
    [_overlayView removeFromSuperview];
}

//depending on what the user has inputed, add or remove the overlayView to the view of the current viewController 
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{   

    if ([searchString length]>0) 
    {
        [self.view addSubview:_overlayView];
    }
    else
    {
        [_overlayView removeFromSuperview];
    }

    return NO;
}

@end

我喜欢这个解决方案比被接受的答案更好,谢谢!更加简洁。 - elsurudo

2
这样简单地实现它怎么样:

只需这样做:

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
self.searchDisplayController.searchResultsTableView.hidden=YES;
return YES;
}

对我来说运行良好...


这只部分起作用,在我的情况下,背景被调暗,一旦我开始输入,调暗的背景就会移除,显示出底层的表视图。 - Besi

2

以下是基于用户182820的代码的我的版本。我隐藏了UISearchDisplayController的表格视图。当在搜索框中输入字符时,我放置一个“暗淡的视图”,使其看起来像UISearchDisplayController的“暗淡的视图”从未消失,然后在搜索完成后将其删除。如果输入一些字符并按取消键,则表格视图会短暂地变成全白色,我不知道如何解决这个问题。

- (void)viewDidLoad {
    ...
    tableViewMask=[UIView new];
    tableViewMask.backgroundColor = [UIColor blackColor];
    tableViewMask.alpha = 0.8;
}

- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller{
    tableViewMask.frame=CGRectMake(self.tableView.frame.origin.x, self.tableView.frame.origin.y+controller.searchBar.frame.size.height, self.tableView.frame.size.width, self.tableView.frame.size.height-controller.searchBar.frame.size.height);
    controller.searchResultsTableView.hidden=YES;
}

- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller{
    [tableViewMask removeFromSuperview];
}

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString{
    if (searchString.length==0)
        [tableViewMask removeFromSuperview];
    else 
        [self.tableView addSubview:tableViewMask];
    [searchText autorelease];
    searchText=[searchString retain];
    return NO;
}   

2

您只需要在UISearchDisplayDelegate中实现以下方法即可,通常这个代理是您的自定义UITableViewController子类。

- (BOOL) searchDisplayController: (UISearchDisplayController *) controller shouldReloadTableForSearchString: (NSString *) searchString
{
    [self startMyCustomWebserviceSearchAsBackgroundProcessForString: searchString]; //starts new NSThread
    return NO; 
}

你试过这个吗?


这样可以防止searchDisplayController发送[searchResultsTableView reload],但不幸的是,searchResultsTableView仍然显示(“无结果”消息)。 - Zargony
很抱歉,我必须说,UISearchDisplayController 的默认行为是无法修改的。 - xoconoxtle
昨天我偶然发现,YouTube应用程序正好符合我的要求。不幸的是,我还没有找到任何好的方法(除了创建UISearchDisplayController)。 - Zargony

1

我找到了更好的方法,因为“最佳答案”存在一个错误 - 当滚动黑色背景表格时,分隔符和“无结果”将被显示。

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {

    controller.searchResultsTableView.backgroundColor = [UIColor blackColor];
    controller.searchResultsTableView.alpha = 0.8;
    controller.searchResultsTableView.separatorStyle = UITableViewCellSeparatorStyleNone;

    for(UIView *subview in tableView.subviews) {
        if([subview isKindOfClass:UILabel.class]) {
            subview.hidden = YES;
        }
    }

    return NO;
}

- (void) searchBarSearchButtonClicked:(UISearchBar *)searchBar {

    self.searchDisplayController.searchResultsTableView.backgroundColor = [UIColor whiteColor];
    self.searchDisplayController.searchResultsTableView.alpha = 1;
    self.searchDisplayController.searchResultsTableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;

    for(UIView *subview in tableView.subviews) {
        if([subview isKindOfClass:UILabel.class]) {
            subview.hidden = NO;
        }
    }

    // search results and reload data ....
}

你可以通过以下方式禁用滚动并解决你提到的“bug”问题:controller.searchResultsTableView.scrollEnabled = NO; - Chris

1

所有现有的答案都太过复杂。你可以立即隐藏结果表视图来解决问题。

-(void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView
{
    tableView.hidden = YES;
}

0

我认为我找到了一个更好的解决方案来解决这个问题。所有之前的答案都正确地显示了一个与UITableView在搜索之前相同的暗淡视图,但每个解决方案都缺乏点击区域以取消搜索的功能。

因此,我认为这段代码更好。

首先,创建一个BOOL变量,例如searchButtonTapped,以指示是否已点击搜索按钮。默认情况下,它是NO。

然后:

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
if (!searchButtonTapped) {        
    // To prevent results from being shown and to show an identical look to how the tableview looks before a search
    [controller.searchResultsTableView setBackgroundColor:[UIColor clearColor]];
    [controller.searchResultsTableView setRowHeight:160];
    self.searchDisplayController.searchResultsTableView.scrollEnabled = NO;
} else {
    // Restore original settings
    [controller.searchResultsTableView setBackgroundColor:[UIColor whiteColor]];
    [controller.searchResultsTableView setRowHeight:44];
    self.searchDisplayController.searchResultsTableView.scrollEnabled = YES;
}

return YES;
}

根据其他答案,现在应该很清楚了。确保用户点击搜索按钮时还原原始设置。

此外,在cellForIndexPath方法中添加:

cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.contentView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.8];

为了创建在输入文本之前显示的相同的暗淡视图。确保将这些属性应用于正确的单元格,即检查哪个UITableView处于活动状态,并且用户尚未点击搜索按钮。
然后,在didSelectRowAtIndexPath中至关重要:
if (tableView == self.searchDisplayController.searchResultsTableView) {
    if (searchButtonTapped) {
           // Code for when the user select a row after actually having performed a search
    {
else 
    [self.searchDisplayController setActive:NO animated:YES];

现在用户可以点击暗淡的区域,这不会导致UITableViewCell被选中,而是取消搜索。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接