【问题标题】:iOS 11 SearchBar in NavigationBar导航栏中的 iOS 11 搜索栏
【发布时间】:2018-01-03 03:19:46
【问题描述】:

在 iOS 11 中,Apple 重新设计了 UISearchBar,使角更圆,高度更大。将 UISearchBar 添加到 navigationBar 非常简单,只需使用 navigationItem.titleView = searchBar 将其设置为 navigationItem 的 titleView。

但是,在 iOS 11 中,它似乎不再按预期工作。 查看我们使用 iOS 10 和 iOS 11 比较相同设置的屏幕

iOS 10

iOS 11

您可以清楚地看到 SearchBar 增加了 NavigationBar 的大小,但条形按钮没有正确对齐。此外,searchBar 不再使用左侧的可用空间。

将 searchBar 放入包装视图以获取 iPad 上的取消按钮,如此处所述Cancel button is not shown in UISearchBar 似乎也不再起作用,因为 searchBar 根本不可见。

如果有人遇到类似问题或已经知道如何解决/改进此问题,我将不胜感激。

这是使用 Xcode 9 Beta 4 构建的。也许未来的版本会解决这个问题。

更新:

由于这个问题没有得到解决,我们决定使用以下解决方案。 我们向 NavBar 添加了一个新的 UIBarButtonItem,然后它呈现了一个新的 ViewController,我们只在其中放置了一个 searchBar,没有其他任何东西到 NavBar 中,这似乎可以工作。使用选定的答案可能是最好的解决方案,因为带有 iOS 11 的 Apple 希望我们使用这个新设计,即使它没有给我们最初想要的结果。另一种可能解决此问题的方法可能是自定义 SearchBar,但这是另一个主题。

【问题讨论】:

  • 我花了几个小时试图解决同样的问题。请在此处查看我的答案:stackoverflow.com/a/53264329/3231194 :) 我将其发布为答案,以便轻松查看。谢谢!

标签: uinavigationbar uisearchbar ios11


【解决方案1】:

iOS 11 中的 navigationItem 上有一个新的 searchController 属性。

https://developer.apple.com/documentation/uikit/uinavigationitem/2897305-searchcontroller

这样使用...

if #available(iOS 11.0, *) {
     navigationItem.searchController = searchController
} else {
     // Fallback on earlier versions
     navigationItem.titleView = searchController?.searchBar
}

在 Objective-C 中,if 语句如下所示:

if (@available(iOS 11.0, *)) {

在 iOS 11 上,如果您未设置 navigationItem.hidesSearchBarWhenScrolling = false,搜索栏最初可能会被隐藏,除非用户向下滚动以显示它。如果您确实将其设置为 false,它会堆叠显示在标题所在的下方,而无需用户滚动。

【讨论】:

  • 我的答案类似于@cook 的答案,但我认为链接和代码可能有助于澄清一点。
  • 这不会给出原始描述的结果。使用 searchController 属性会将搜索栏放在导航下方。
  • 这适用于 iPhone,但不适用于我的 iPad。
  • 你知道这种情况下的导航栏高度吗?会改变吗?
【解决方案2】:

在 iOS 11 中可以通过添加高度 44 的约束来改变 UISearchBar 的高度:

if #available(iOS 11.0, *) {
    searchBar.heightAnchor.constraint(equalToConstant: 44.0).isActive = true
}

【讨论】:

  • 这使得顶部和底部边框更短。我尝试了这个objective-c解决方案:[[self.notesSearchBar.heightAnchor constraintEqualToConstant:44.0] setActive:YES],但我不喜欢这个解决方案,因为它使顶部底部边距变薄和奇怪。
  • 这对我有用。它重新定位我的搜索栏,保持正确的布局。
  • 这是正确的解决方案,特别是如果您的应用同时针对 iOS 10 和 iOS 11
  • 这解决了高度问题,但没有解决作者发布的宽度问题。
【解决方案3】:

我遇到了同样的问题,在谷歌上搜索了几天后,我找到了这个页面 - https://translate.google.com/translate?hl=en&sl=zh-CN&u=http://www.jianshu.com/p/262f6e34a7d3&prev=search

这个页面指向这个 git repo - https://github.com/DreamTravelingLight/searchBarDemo - 这个演示项目展示了如何使用 titleView 的旧方法来仍然有一个没有大小问题的 searchBar。

关键是这些

_searchBar = [self addSearchBarWithFrame:CGRectMake(0, 0, kScreenWidth - 2 * 44 - 2 * 15, 44)];
UIView *wrapView = [[UIView alloc] initWithFrame:_searchBar.frame];
[wrapView addSubview:_searchBar];
self.navigationItem.titleView = wrapView;

如果您将 UISearchBar 嵌入到视图中,并将该 wrapView 设置为 titleView,则 UISearchBar 将具有您为其设置的大小,并将按预期适合导航栏。

谢谢, 大卫

【讨论】:

  • 为什么是 kScreenWidth - 2 * 44 - 2 * 15?
【解决方案4】:

如果您真的想在 iOS 11+ navigationBar 中使用原生 UISearchBar(并避免创建自定义组件的需要),您可以为该 @ 创建一个容器视图987654323@ 可以完全控制框架。此容器视图将是您传入的 searchBar 的超级视图。

类似:

class SearchBarContainerView: UIView {

    let searchBar: UISearchBar

    required init?(coder aDecoder: NSCoder) {
        searchBar = UISearchBar()
        super.init(coder: aDecoder)
    }

    init(searchBar: UISearchBar) {
        self.searchBar = searchBar
        super.init(frame: CGRect(x: 0.0, y: 0.0, width: 0.0, height: 44.0))
        addSubview(searchBar)
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        searchBar.frame = bounds
    }
}

然后:

let containerView = SearchBarContainerView(searchBar: searchController.searchBar)
containerView.frame.size.width = navigationController?.navigationBar.frame.size.width ?? 0.0
navigationItem.titleView = containerView

注意,这只是一个快速演示,不适合navigationBar 帧更改(显示旋转等)。你可以用例如解决这个问题autoresizingMask.

【讨论】:

  • 这行得通!另外更新override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { coordinator.animate(alongsideTransition: { // here }... } 中的containerView.frame就够了。
【解决方案5】:

在 iOS 14+ 中做总结

首先修复推送导致额外高度:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    navigationController?.view.setNeedsLayout() // force update layout
    navigationController?.view.layoutIfNeeded() // to fix height of the navigation bar
}

第二次修复pop到原点高度:

extendedLayoutIncludesOpaqueBars = true

以上所有代码都设置在带有搜索栏的控制器中。

【讨论】:

    【解决方案6】:

    我认为您必须将新的 UINavigationItem.searchController 属性设置为您的 UISearchController 对象。这就是您如何获得消息中所见的新效果。看起来旧的行为已经完全消失了。我希望我是错的,但是整个 API 对 11 进行了大修。我知道它通常有问题,所以如果这个问题得到修复,我们将看到更新的 beta 和 GM。 (在 Beta 6 时编写)

    【讨论】:

      【解决方案7】:

      这对我有帮助:

          if ([self.navigationItem respondsToSelector:@selector(setSearchController:)])
          {
              [self.navigationItem performSelector:@selector(setSearchController:) withObject:self.searchController];
          }
          else
          {
              self.tableView.tableHeaderView = self.searchController.searchBar;
          }
      

      【讨论】:

        【解决方案8】:

        我尝试了searchControllersearchBar,但发现searchBar 符合我的要求(点击搜索按钮进行搜索)。

        -(void)searchBarSetUp{
        //Search button to reload the radio content.
        self.searchButton.action = @selector(addSearchBarToNavigationTitleView);
        self.searchButton.target = self;
        
        //search bar initialization
        searchBar = [[UISearchBar alloc] initWithFrame:CGRectZero];
        searchBar.delegate = self;
        searchBar.showsCancelButton = YES;
        [searchBar sizeToFit]; }
        
        -(void)addSearchBarToNavigationTitleView {
        // Install the search bar as the table header.
        self.navigationItem.titleView = searchBar;}
        

        如果我使用searchControl,我也遇到了处理黑屏的困难。

        【讨论】: