UISearchController 不会在旋转时重新显示导航栏

Posted

技术标签:

【中文标题】UISearchController 不会在旋转时重新显示导航栏【英文标题】:UISearchController Not Redisplaying Navigation Bar on Rotate 【发布时间】:2015-02-17 00:57:02 【问题描述】:

我已经实现了 UISearchController,它工作得很好,除了...

当我点击搜索栏时,导航栏按预期消失。当我将手机旋转到横向视图时,我得到了这个有意义的视图。

但是,当我将手机旋转回纵向视图(仍然在搜索类型区域中选择)时,我会看到以下视图。

您可以看到导航栏不再出现。我觉得我正在实现一个基本的搜索控制器。 可能是什么原因造成的?

self.venueSearchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.venueSearchController.searchResultsUpdater = self;
self.venueSearchController.searchBar.delegate = self;
self.venueSearchController.dimsBackgroundDuringPresentation = NO;
self.venueSearchController.hidesNavigationBarDuringPresentation = YES;
self.venueSearchController.searchBar.frame = CGRectMake(self.venueSearchController.searchBar.frame.origin.x, self.venueSearchController.searchBar.frame.origin.y, self.venueSearchController.searchBar.frame.size.width, 44.0);

self.definesPresentationContext = YES;

self.navigationController.navigationBar.translucent = YES;
self.venueSearchController.searchBar.translucent = YES;

self.tableView.tableHeaderView = self.venueSearchController.searchBar;

【问题讨论】:

这是 UISearchController 的默认行为,当搜索类型区域处于活动状态时导航栏隐藏,点击取消时导航栏显示,这是你的行为吗? 不,我的问题是,在第二个屏幕截图中,搜索栏位于时间/电池/运营商标题后面,这是不正确的 Reson for your search bar is behind the time/battery/carrier header is you given height = 44 for your searchBar.frame,它认为它应该是 64,因为状态栏从顶部占据 20px 高度。 不,我不相信这是正确的。将手机旋转回纵向模式后,UI 搜索控制器应自动重置导航栏高度 @aherrick 您已经设置了 searchBar 委托,但没有实现必要的方法。请参阅下面的答案 【参考方案1】:

当状态栏重新出现时,UISearchController 似乎忘记重置searchBar 的框架。我认为这可能是UISearchController 中的一个错误; radar 中似乎列出了一些。似乎 searchBar 的超级视图(在 UISearchController 内部)以错误的高度结束。这很烦人,因为解决方案因此涉及到 searchController 的视图层次结构,Apple 可以更改它......您可能想要添加对 ios 版本的检查,以便它仅针对指定版本运行。

如果您将以下代码添加到您的视图控制器,它将在 trait 集合更改时被调用。它检查 a) 搜索控制器是否处于活动状态,b) statusBar 未隐藏,c) searchBar origin-y 为 0,如果是这样,它将超级视图的高度增加 statusBar 的高度,它移动搜索栏向下。

override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) 
    let app = UIApplication.sharedApplication()
    if searchController!.active && !app.statusBarHidden && searchController?.searchBar.frame.origin.y == 0 
        if let container = self.searchController?.searchBar.superview 
            container.frame = CGRectMake(container.frame.origin.x, container.frame.origin.y, container.frame.size.width, container.frame.size.height + app.statusBarFrame.height)
        
    

目标 C

- (void) traitCollectionDidChange: (UITraitCollection *) previousTraitCollection 

    [super traitCollectionDidChange: previousTraitCollection];

    if(self.venueSearchController.active && ![UIApplication sharedApplication].statusBarHidden && self.venueSearchController.searchBar.frame.origin.y == 0)
    
        UIView *container = self.venueSearchController.searchBar.superview;

        container.frame = CGRectMake(container.frame.origin.x, container.frame.origin.y, container.frame.size.width, container.frame.size.height + [UIApplication sharedApplication].statusBarFrame.size.height);
    

【讨论】:

感谢您的想法。这只是一种 Swift 方法吗?试图找到这个的Objective C版本,我会试一试! 抱歉,不知什么原因,我以为您使用的是 Swift。但它在 Obj-C 中可用。它位于 UIViewController 采用的协议中(除其他外)。苹果文档是here。 看起来这可能正是我所需要的!这是我目前正在测试的 ObjC 版本。会继续玩它,但如果它看起来不错 +50 @aherrick 我希望它能完成这项工作。我记得昨晚在床上的超级电话,但忘记将其添加到我的答案中。但是您已经对其进行了排序。 当旋转 180 度时,上面的代码对我不起作用。所以我也在 didRotatefunction 中使用了容器名声更改代码。【参考方案2】:

您可能需要在视图控制器中实现UIBarPositioningDelegate

self.venueSearchController.searchBar.delegate = self;

searchBar 正在寻找来自它的委托的响应。

@protocol UISearchBarDelegate <UIBarPositioningDelegate> 

将以下内容添加到您的self(我假设它是一个 ViewController)

#pragma mark - <UIBarPositioningDelegate>

// Make sure NavigationBar is properly top-aligned to Status bar
- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar

    if (bar == self.venueSearchController.searchBar) 
        return UIBarPositionTopAttached;
    
    else  // Handle other cases
        return UIBarPositionAny;
    

【讨论】:

很好的解决方案。我相信UISearchController 没有传递足够的信息来帮助视图控制器正确显示搜索栏!虽然我们将 searchBar 直接注入到 tableView 的标题中,但我想这是最常见的情况!我想它们一定是从这个角度设计的。【参考方案3】:

我认为这可能是 UITableViewController 布局处理导航栏的方式的问题,而不是在您旋转的情况下出现导航栏时没有导航栏。

我认为您可以通过将 UITableViewController 替换为 UIViewController 来解决此问题,并将 UITableView 放入其中。然后将表格视图的顶部约束设置为顶部布局指南。将边约束设置为 0 的左、右、下。

这应该确保表格始终位于状态栏下方,并且在导航栏移动和返回时仍能正确移动。

查看此讨论:iOS 7: UITableView shows under status bar

【讨论】:

【参考方案4】:

UISearchControllernavigationItem 一起使用时,我遇到了类似的问题。它看起来不同,但由相同的问题引起:UISearchController 在状态栏重新出现时不会更新searchBar 框架。

但是,与其手动调整 searchBar 的视图层次结构的框架,不如通过在 traitCollectionDidChangeviewWillTransition(to size: CGSize, with cooridnator: UIViewControllerTransitionCoordinator) 中来回切换 hidesNavigationBarDuringPresentation 来强制它更新布局:

所以修复看起来像这样:

 override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) 
    super.traitCollectionDidChange(previousTraitCollection)
    if #available(iOS 11, *) 
        navigationItem.hidesSearchBarWhenScrolling.toggle()
        navigationItem.hidesSearchBarWhenScrolling.toggle()
    

这是原始问题的样子。

然后旋转得到这个:

【讨论】:

【参考方案5】:

我通过在设置中关闭“隐藏状态栏”暂时“修复”了这个问题。

【讨论】:

以上是关于UISearchController 不会在旋转时重新显示导航栏的主要内容,如果未能解决你的问题,请参考以下文章

当我删除它们时,UISearchController 不会删除结果

UISearchController 中的 UISearchBar 不会消失

在 iOS 11 上以编程方式滚动 UISearchController 的搜索栏不会消失

如何向 UISearchController 添加间隙?

移除 UISearchController 后,NavigationItem 不会恢复到原来的大小

Swift UISearchController tableview 搜索结果滚动不会在键盘上方移动到最后一行