以编程方式显示 UISearchController 的搜索栏

Posted

技术标签:

【中文标题】以编程方式显示 UISearchController 的搜索栏【英文标题】:Display UISearchController's searchbar programmatically 【发布时间】:2015-07-08 04:26:51 【问题描述】:

注意 1:这个问题涉及在它更新的表视图之外添加 UISearchController 的搜索栏 - 不是作为表视图的标题。

注意 2:一些试验和错误使我找到了解决方案。请在下方查看我的answer。

我是 ios 开发新手,正在努力使用 UISearchController 类。我有一个视图控制器,在我的视图控制器的视图中,我计划在表格视图上方有一个搜索栏。我希望搜索栏链接到 UISearchController。由于界面生成器不附带 UISearchController,我以编程方式添加控制器。实例化 UISearchController 后,我尝试以编程方式将搜索控制器的搜索栏添加到我的视图中,但没有成功。我尝试设置搜索栏的框架并为其提供自动布局约束,但两种方法都对我不起作用(即,当我运行应用程序时,什么都没有出现)。这是我尝试过的最新代码:

    let searchController = UISearchController(searchResultsController: nil)

    // Set the search bar's frame
    searchController.searchBar.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 50)

    // Constraint to pin the search bar to the top of the view
    let topConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
    searchController.searchBar.setTranslatesAutoresizingMaskIntoConstraints(false)

    self.view.addSubview(searchController.searchBar)

    self.view.addConstraint(topConstraint)

任何帮助将不胜感激!谢谢!

编辑: 仅使用其中一个设置搜索栏的框架或给它自动布局约束(而不是我最初尝试的组合)似乎一开始可以工作,但在点击之后正如 Dwight 所指出的那样,您将在搜索栏中遇到问题。我已经留下了这些案例的代码,以防与您当前拥有的代码进行比较会有所帮助,但对于一个可行的解决方案,请参阅下面的答案。

使用自动布局约束:

    let searchController = UISearchController(searchResultsController: nil)

    let topConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: (statusBarHeight + navigationBarHeight!))
    let leftConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 0)
    let rightConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 0)
    let heightConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 44)
    searchController.searchBar.setTranslatesAutoresizingMaskIntoConstraints(false)

    searchController.searchBar.addConstraint(heightConstraint)

    self.view.addSubview(searchController.searchBar)

    self.view.addConstraints([topConstraint, leftConstraint, rightConstraint])

我已将 topConstraint 常量设置为状态栏的高度加上导航栏的高度,因为我的视图控制器嵌入在导航控制器中。

调整框架:

    let searchController = UISearchController(searchResultsController: nil)

    searchController.searchBar.frame = CGRect(x: 0, y: (statusBarHeight + navigationBarHeight!), width: self.view.frame.size.width, height: 44)

    self.view.addSubview(searchController.searchBar)

【问题讨论】:

试试这个link1,link2可能对你有帮助 @Anbu.Karthik 感谢您的链接!第一个似乎只是我想要的,需要更多的界面构建器参与,所以我会仔细看看。我第二次使用 UISearchDisplayController,我认为它在 iOS 8 中已被弃用。 我遇到了和你一样的问题,但是在用户点击搜索栏后我遇到了问题。使用 frame 选项,搜索栏会向上滑出视图,并且 tableview 会显示但位置不正确。使用约束选项时,应用程序会因“视图层次结构未为约束做好准备:”错误而崩溃。您是否也遇到过这些问题? @Dwight - 谢谢。你是对的 - 编辑 1 中的解决方案都不起作用。我已经确认了您遇到的相同问题。请参阅编辑2!这对我来说似乎效果很好。让我知道这是否适合您! @kcstricks - 哇,非常感谢您的回复,我认为这将是一个失败的原因。编辑 2 工作出色,干得好!用 UISearchController 来获得 UISearchDisplayController 的功能真是太痛苦了!您绝对应该发布编辑 2 作为此问题的答案以帮助其他人。再次感谢! 【参考方案1】:

经过反复试验,我得到了以下可行的解决方案:

    打开 Main.storyboard 并向视图控制器添加一个高度为 44 的 UIView(UISearchBar 的默认高度)和一个 UITableView。设置自动布局约束,以便将 UIView 固定到两侧和顶部布局指南(使用顶部布局指南确保无论您的视图控制器是否嵌入导航控制器中都能正常工作)并且表格视图固定到两侧,底部布局指南,其顶部固定在 UIView 的底部。 在 ViewController.swift 中将 UIView 和 UITableView 连接为 IBOutlets。在我的项目中,我称它们为 topView 和 tableView。 在 ViewController.swift 的顶部声明一个搜索控制器:var searchController: UISearchController!

    然后,在 viewDidLoad() 中,你需要:

    // Initialize and set up the search controller
    self.searchController = UISearchController(searchResultsController: nil)
    self.searchController.searchResultsUpdater = self
    self.searchController.dimsBackgroundDuringPresentation = false // Optional
    self.searchController.searchBar.delegate = self
    
    // Add the search bar as a subview of the UIView you added above the table view
    self.topView.addSubview(self.searchController.searchBar)
    // Call sizeToFit() on the search bar so it fits nicely in the UIView
    self.searchController.searchBar.sizeToFit()
    // For some reason, the search bar will extend outside the view to the left after calling sizeToFit. This next line corrects this.
    self.searchController.searchBar.frame.size.width = self.view.frame.size.width
    

应该是这样的!当然,您需要使您的视图控制器成为 UITableViewDatasource、UITableViewDelegate、UISearchBarDelegate、UISearchControllerDelegate 和 UISearchResultsUpdating 并处理所有必需的委托方法,但就搜索栏而言,这对我有用。如果您有任何问题,请发表评论。

【讨论】:

"// 出于某种原因,搜索栏将延伸到左侧视图之外"。这样做是因为在 viewDidLoad() 中,视图的框架尚未正确计算,尽管您的搜索栏得到了一个错误的框架,该框架比应有的大得多。如果您想正确地制作这些东西,请在您的 viewDidAppear 中或在您的视图完成布局之后制作 sizeToFit()。 @Fawkes - 感谢您的意见。我有一个快速的后续问题要问你:如果是这种情况,并且当我调用 sizeToFit() 时还没有正确计算视图的框架,那么你知道为什么将 searchBar 的宽度设置为宽度以下代码行的视图?如果此时仍无法正确计算视图的框架,那么上述方法不应该不起作用吗? 不幸的是找不到关于 sizeToFit() 的非常详细的信息,但正如它所写的那样 ->“调整并移动接收器视图,使其仅包含其子视图。”这可能意味着在“layoutIfNeeded()”的情况下会发生强制帧计算,因此在调用“sizeToFit()”之后,您会获得在正常发生之前计算帧的视图,例如在“viewDidLayoutSubviews”之后或“viewDidAppear”。 当我这样做并点击搜索栏时,搜索栏会像 80 点一样向下跳。当我取消搜索时,它会回到原来的位置。有谁知道如何解决这个问题? @coolcool1994 您好,您解决了搜索栏像 80 分一样跳下的问题吗?我在 iOS 12 中遇到了同样的问题。【参考方案2】:

试试这个:

        let searchController = UISearchController(searchResultsController: nil).searchBar

        // Set the search bar's frame
        searchController.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 50)

        // Constraint to pin the search bar to the top of the view
        let topConstraint = NSLayoutConstraint(item: searchController, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
//        searchController.setTranslatesAutoresizingMaskIntoConstraints(false)

        self.view.addSubview(searchController)
//        self.presentViewController(searchController, animated: true, completion: nil)

        self.view.addConstraint(topConstraint)

或者你可以这样做:

    searchController.searchBar.setTranslatesAutoresizingMaskIntoConstraints(false)   
->  searchController.searchBar.setTranslatesAutoresizingMaskIntoConstraints(true)

【讨论】:

感谢您的帮助!我对您的第一个建议感到有些困惑,因为这似乎只是添加了一个搜索栏,而不是与搜索控制器关联的搜索栏。如果我错了,请纠正我。至于您的第二个建议,只要您指定了它的框架,将 setTranslatesAutoResizingMaskIntoConstraints 设置为 true 即可显示搜索栏。但是,我相信默认情况下这个标志是真的,所以我认为你可以像我在我的帖子的 EDIT 1 中所做的那样指定一个框架并将这条线去掉。

以上是关于以编程方式显示 UISearchController 的搜索栏的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式显示/隐藏 BottomAppBar?

UIImageView(以编程方式创建)未显示

以编程方式创建和显示 ProgressBar

允许在以模式方式显示的以编程方式创建的视图内自动旋转

使用 React native 以编程方式显示键盘

滚动 UITextView 以显示以编程方式添加的新文本