在Swift中将搜索栏放置在导航栏中

64

所以我已经尝试了各种方法来在Swift中将搜索栏放入导航栏中。但很遗憾,我还没有让它工作起来...

对于那些不知道我在说什么的人,我正在尝试做类似这样的事情

enter image description here

注意导航栏中的搜索栏。所以这是我目前正在使用的

self.searchDisplayController?.displaysSearchBarInNavigationBar = true

我把那个放在了viewDidLoad里,但是当我启动应用时,只出现了一个空的导航栏.... :( 有什么建议吗?

我将其添加到viewDidLoad中后,启动应用程序时只显示一个空的导航栏.... :( 有什么想法吗?

10个回答

77

试一试

let leftNavBarButton = UIBarButtonItem(customView:Yoursearchbar)
  self.navigationItem.leftBarButtonItem = leftNavBarButton

更新

你保留了一个懒惰的UISearchBar属性

lazy   var searchBar:UISearchBar = UISearchBar(frame: CGRectMake(0, 0, 200, 20))

在viewDidLoad中

searchBar.placeholder = "Your placeholder"
var leftNavBarButton = UIBarButtonItem(customView:searchBar)
self.navigationItem.leftBarButtonItem = leftNavBarButton

如果你想使用故事板,只需将搜索栏拖动到outlet中,然后将lazy属性替换为你的outlet搜索栏即可。


1
你只需要更改搜索栏的属性来添加占位符。我会更新答案。 - Leo
1
你好,能给我展示一下这个代码的全部内容吗?我不太理解lazy部分。 - Gibran
有人能告诉我如何添加“lazy”部分吗?就像被接受的答案末尾所提到的那样。谢谢。 - bably
1
有人能解释一下 lazy 是什么意思吗?lazy var searchBar 和 var searchBar 有什么区别? - Happiehappie
不要将searchBar放置到leftBarButtonItem中,这会导致各种问题。请按照antonio081014提供的建议进行操作。 - deeJ
显示剩余5条评论

65
    // create the search bar programatically since you won't be
    // able to drag one onto the navigation bar
    searchBar = UISearchBar()
    searchBar.sizeToFit()

    // the UIViewController comes with a navigationItem property
    // this will automatically be initialized for you if when the
    // view controller is added to a navigation controller's stack
    // you just need to set the titleView to be the search bar
    navigationItem.titleView = searchBar

这是比其他任何解决方案都更好的方法。 - Profstyle
@antonio081014,兄弟,你能帮我看一下我的问题吗?https://stackoverflow.com/questions/46375778/add-navigation-bar-in-uicollectionview-in-swift-4-ios-11 - May Phyu

31

使用Swift 5、XCode 11和Storyboard,您可以通过Storyboard轻松添加搜索栏属性,并且在视图控制器类中有更少的代码

1.) 将搜索栏视图作为外部视图添加到视图控制器中。

enter image description here

2.) 将searchBarView连接到您的视图控制器。

enter image description here

3.) 将搜索栏视图添加到导航栏标题项中。

navigationItem.titleView = searchBarView

结果:

在此输入图像描述


4
我希望我能够给这个更多的点赞。我从不知道你可以做到这个!! - ghostatron
2
@Egzon,这个问题是将导航栏的大小从44更改为56。所以当我返回到上一个视图控制器时,会看到导航控制器更新到其原始大小44的闪烁。请问有什么建议吗? - Mitesh Dobareeya
嗨@MiteshDobareeya,我下周会检查问题并回复您。您是否在同一个UINavigationViewController中推送视图控制器? - Egzon P.
2
@EgzonP。是的,我正在将它推入同一个UINavigationViewController中。主根视图控制器导航栏的大小为44,当我推送第二个视图控制器并添加搜索栏时,第二个视图控制器的导航栏大小增加到56。因此,当我弹回到第一个视图控制器时,它的导航栏会闪烁。 - Mitesh Dobareeya

25

在您的视图控制器中:

lazy var searchBar = UISearchBar(frame: CGRectZero)

override func viewDidLoad() {
    super.viewDidLoad()

    searchBar.placeholder = "Search"

    navigationItem.titleView = searchBar
}

通过设置navigationItem.titleView的方式,可以使搜索栏自动居中于iPhone和iPad设备上。注意:仅在v8.4和v9.0版本进行了测试。

适用于SWIFT 3

lazy var searchBar = UISearchBar(frame: CGRect.zero)

当用户点击“取消”按钮时,如何从navigationItem.titleView中移除它? - Satyam
同样的问题 ^ - Nikhil Sridhar
1
从我现在所知,如果你说的是搜索栏取消按钮。实现UISearchBarDelegate函数searchBarCancelButtonClicked(:),在该函数中调用navigationItem.titleView = nil。这应该会移除搜索栏,如果你所指的是“移除”。对于正常的搜索栏功能,还要确保实现searchBarSearchButtonClicked(:),并添加searchBar.resignFirstResponder()以在单击搜索按钮(或通过按下返回键开始搜索)时移除键盘。 - iAmcR
1
Swift 3 的更新代码: 懒加载变量 searchBar = UISearchBar(frame: CGRect.zero) - DoesData

22

在2019年,您应该使用UISearchController。

override func viewDidLoad() {
    super.viewDidLoad()

    let searchController = UISearchController(searchResultsController: nil)
    searchController.searchResultsUpdater = self.viewModel
    searchController.obscuresBackgroundDuringPresentation = false
    searchController.searchBar.placeholder = "Search artists"
    self.navigationItem.searchController = searchController
    self.definesPresentationContext = true
}

有些类应该符合UISearchResultsUpdating。我通常将其作为扩展添加到我的ViewModel中。

extension ArtistSearchViewModel: UISearchResultsUpdating {

func updateSearchResults(for searchController: UISearchController) {
    print("Searching with: " + (searchController.searchBar.text ?? ""))
    let searchText = (searchController.searchBar.text ?? "")
    self.currentSearchText = searchText
    search()
    }
}

这将产生类似于以下内容的东西:

搜索栏


这个解决方案很好,但是当我的tableView只有几行并且高度显然不够时,我遇到了一个问题。当我向下滚动时,搜索栏会消失,然后我无法通过再次向上滚动来获取它,因为它不需要滚动以显示所有行。有什么想法如何解决这个问题吗? - JDK92
@JDK 很遗憾,我不确定。:( 你可以尝试观察下拉刷新,当它被触发时,你可以尝试手动告诉 UISearchBar 显示。我只是提供一个想法。 - Martin Berger
@JDK92 我知道这是一个晚回答,但如果你想要搜索栏始终保持粘性,你可以使用这个navigationItem.hidesSearchBarWhenScrolling = false。 - mike vorisis

11

适用于iOS 11及以上版本

navigationItem.searchController = searchController

在此输入图片描述

iOS 10及以下版本

navigationItem.titleView = searchController.searchBar;

输入图像描述

或者您可以按这个答案所述将其分配为leftBarButtonItem。


3

针对 Swift 5 及其以上版本

此外,您可以使用以下代码。 完全以编程方式实现

import UIKit

class SearchTableViewController: UITableViewController {

private lazy var searchController: UISearchController = {
    let sc = UISearchController(searchResultsController: nil)
    sc.searchResultsUpdater = self
    sc.delegate = self
    sc.obscuresBackgroundDuringPresentation = false
    sc.searchBar.placeholder = "Enter A Compiny Name Or Symbole"
    sc.searchBar.autocapitalizationType = .allCharacters
    return sc
}()

override func viewDidLoad() {
    super.viewDidLoad()
    setupNavigationBar()
}

   private func setupNavigationBar() {
       navigationItem.searchController = searchController
   }

 }

// MARK: - UISearchResult Updating and UISearchControllerDelegate  Extension
  extension SearchTableViewController: UISearchResultsUpdating, UISearchControllerDelegate {
    func updateSearchResults(for searchController: UISearchController) {
    
    }
 }

After Clicking Search

After Clicking Cancel Button In Search


2
    let searchBar = UISearchBar()
    searchBar.sizeToFit()
    searchBar.placeholder = ""
    self.navigationController?.navigationBar.topItem?.titleView = searchBar

0
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {

    searchBar.endEditing(true)
    searchBar.text = nil
    print("## search btn clicked : \(searchBar.text ?? "")")
} 

2
感谢您提供这段代码片段,它可能会提供一些有限的、即时的帮助。通过展示为什么这是一个好的解决方案,适当的解释将极大地提高其长期价值,并使其对未来具有类似问题的读者更有用。请编辑您的答案,添加一些解释,包括您所做的假设。 - Toby Speight

0

将SearchBar设置为titleView会改变navigationBar的高度为56。要解决这个问题,您可以将searchBar嵌入视图中,并将其设置为titleView。

    var offset: CGFloat = 20

    // If VC is pushed, back button should be visible
    if navigationController?.navigationBar.backItem != nil {
        offset = 40
    }

    let customFrame = CGRect(x: 0, y: 0, width: view.frame.size.width - offset, height: 44.0)
    let searchBarContainer = UIView(frame: customFrame)
    searchBar = UISearchBar(frame: customFrame)
    searchBarContainer.addSubview(searchBar)
    navigationItem.titleView = searchBarContainer

解决方案一般般,因为在这种情况下你可能需要使用 rightBarButtonItems,并且 frame 不太合适。 - Gargo

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