iOS 7在导航栏中的搜索栏不显示取消按钮

20
在一个应该在iOS 6和iOS 7上运行的应用程序中,如果该应用程序在iOS 7上运行,则导航栏中嵌入的搜索栏的取消按钮不再显示。而在iOS 6上它是有效的。
搜索栏位于导航栏的标题视图中,如果搜索栏变为第一响应者,则应显示取消按钮: iOS 7 enter image description here iOS 6 enter image description here 在独立的测试用例中,代码非常简单:
@interface MyViewController : UITableViewController<UISearchBarDelegate>

@property (nonatomic) IBOutlet UISearchBar* searchBar;

@end


@implementation MyViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.navigationItem.titleView = self.searchBar;
}

- (void) searchBarTextDidBeginEditing: (UISearchBar*) searchBar {
    [searchBar setShowsCancelButton: YES animated: YES];
}

@end

这是我在文档中错过的iOS 7中的有意更改吗?如果是,应该有什么替代方案?

如果不是,那么我的代码是否出错了?


你是否为 UISearchBar 设置了代理? - ppaulojr
2
是的,我已经在Interface Builder中设置了代理,并且searchBarTextDidBeginEditing:按预期被调用。否则,在iOS 6上它将无法工作。 - Codo
8个回答

14

看起来你做的一切都是正确的,但显然苹果在iOS 7中改变了一些东西。根据这个SO问题,在iOS 7中,嵌入到UINavigationBar中的UISearchBar不会显示取消按钮。

根据开发者文档showsCancelButton属性可能与setShowsCancelButton:Animated方法略有不同的效果。试试这样做:

searchBar.showsCancelButton = YES;
[searchBar setShowsCancelButton:YES animated:YES];

我不确定那会有任何影响。您也可以尝试将代码放置在另一个委托方法中:

- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar; // return NO to not become first responder
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar; // called when text starts editing

您可能还想查看iOS 7更新日志。看起来苹果更改了一个UISearchDisplayController / UISearchBar在添加到UINavigationBar时的行为。请查看UIKit部分下的最后一条项目(尽管不清楚究竟更改了什么)。


您也可以尝试使用UISerachDisplayController。更简单的方法是将UISearchBar嵌入到UITableView的标题中。


1
“showsCancelButton属性与setShowsCancelButton:Animated方法不同” - 你在文档中哪里看到的?该方法是一种带有动画设置属性的方式。 - Bryan
感谢您提出的所有想法。我无法确认 showsCancelButtonsetShowsCancelButton: animated: 之间没有关联。如果我使用您的代码,在iOS 7上问题仍然存在,而在iOS 6上的动画不再起作用。将代码移动到其他委托方法也没有任何效果。 iOS 7日志中的最后一个要点是我知道的一项改进,但它不会影响我的问题,因为我没有使用 UISearchDisplayController - Codo
你最好的提示是提到了其他SO问题的参考。这样,取消按钮就会出现。然而,搜索栏的样式会改变,搜索栏的适当大小需要额外的努力。如果搜索栏嵌入导航栏中,它似乎故意表现得不同。了解这种变化背后的想法将是有趣的。 - Codo
我接受了你的答案,因为它包含了最相关的信息。但是,我采用了不同的方法: 在iOS 7中,我现在把搜索栏添加到表视图的头部(而不是导航栏)。这似乎是最简单的方法,使取消按钮可见。我还尝试使用UISearchDisplayController,但它有太多问题(例如,如果表视图没有滚动到最顶部,则会忽略轻击)。 - Codo

12

我很简单地解决了这个问题,只需添加 rightBarButtonItem :)

self.navigationItem.titleView = self.searchBar;
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Cancel", nil) style:UIBarButtonItemStylePlain target:self action:@selector(didClickCancelButton:)] autorelease];

但是你必须检查当前的iOS版本是否>= 7.0,否则会出现两个“取消”按钮。

顺便说一下,这种方法允许你拥有始终可用的“取消”按钮。


1
我喜欢这个答案。它保持简单,不试图与内置行为抗争,并且给您完全的控制权。 - zekel
简单而优雅。思维精妙! - Aron

2
如果您正在使用UISearchBar与UISearchDisplayController,您可以在“searchDisplayControllerWillBeginSearch”委托方法中设置取消按钮显示,如下所示:(已测试iOS 7)
-(void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller{
    controller.searchBar.showsCancelButton = YES;
}

如果UISearchBar位于导航栏中,则不会显示取消按钮。在这种情况下,UISearchDisplayController无法帮助解决问题。如果将UISearchBar放置在UITableView的标题中,并与UISearchDisplayController结合使用,则会显示取消按钮,但是如果UITableView的滚动视图未定位在顶部,则该按钮不会响应点击事件。这有点混乱。 - Codo

2

iOS 7与iOS 6在导航栏上有所不同,如果您想在导航栏中显示UISearch bar,则可以尝试以下方法:

将您的UISearchbar放置在一个UIView上,如[self.searchView addSubview self.searchBar],然后将导航栏的titleView设置为您的searchView,如self.navagitioncontroller.navigationItem.titleView = self.searchView

希望这对您有用。


1

我认为这是一个错误。以下是我的解决方法。它不是完美的,但适用于 iOS 6&7。在 iOS7 上,搜索栏文本字段在淡出时会滑动到取消按钮上,而在 iOS6 上,文本字段的宽度扩展不是动画效果。

@interface FTViewController ()
@property(nonatomic, strong) UISearchBar *searchBar;
@end

@implementation FTViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.searchBar = [[UISearchBar alloc] init];
    self.searchBar.delegate = self;

    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_6_1) {
        // iOS 6.1 and older (only tested on 6.1)
        [self.searchBar sizeToFit];
        self.searchBar.backgroundImage = nil;
    }

    self.navigationItem.titleView = self.searchBar;
}

-(void)cancelBarButtonItemClicked:(id)sender
{
    [self searchBarCancelButtonClicked:self.searchBar];
}

-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
    [searchBar resignFirstResponder];
    [self.navigationItem setRightBarButtonItem:nil animated:YES];
}

-(BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
    UIBarButtonItem *cancelBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelBarButtonItemClicked:)];
    [self.navigationItem setRightBarButtonItem:cancelBtn animated:YES];

    return YES;
}
@end

1

这确实是一个bug,在7.1版本中已经修复。


1

在iOS6和iOS7之间似乎存在变化,即从xxxDidYYY方法对UI的更改有时不起作用,您需要在xxxWillYYY方法或在一些代码(例如块或短延迟后)中执行的主事件循环中进行操作以使其起作用。

在您的情况下,请尝试以下操作:

- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
    searchBar.showsCancelButton = YES;
    return YES;
}

1
我尝试了你的代码,但它没有改变任何东西。即使我将搜索栏配置为始终显示取消按钮,它也不会显示。因此,问题似乎与使用的委托方法无关。 - Codo

1

有两个选项:

  1. 将搜索栏添加为uiviewcontroller.view的子视图,并在需要时隐藏导航栏
  2. 将取消按钮添加到uiviewcontroller.navigationItem.rightBarButtonItem

我更喜欢第二个选项,但第一个选项看起来更本地化。


因为我有其他需要显示的导航栏按钮项,所以我选择了选项2。 - DonnaLea

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