2

I want to achieve something very simple: a search bar in the navigation bar, with a Cancel button that shows when the bar is activated.

I am using a UISearchController, and currently I have the following:

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

  let searchController = UISearchController(searchResultsController: nil)
  searchController.searchResultsUpdater = self
  searchController.delegate = self
  searchController.searchBar.delegate = self
  searchController.hidesNavigationBarDuringPresentation = false
  searchController.searchBar.sizeToFit()
  self.navigationItem.titleView = searchController.searchBar
  self.definesPresentationContext = true
}

The search bar shows. However, if I focus on it no Cancel button is shown, and no delegate methods are called whatsoever. That is, no methods in the UISearchResultsUpdating, UISearchControllerDelegate, or UISearchBarDelegate protocols are called, although I've set self to respond to all of them.

If I put the following line into viewDidLoad, the delegate methods start to function:

self.navigationItem.searchController = searchController

However, then I can't put the search bar inside the navbar. It's shown under the navbar instead.

I've searched extensively in SO but nothing seems to work for me. I may be missing something obvious here - how can I make it work? Thanks!

Hitesh Surani
  • 12,733
  • 6
  • 54
  • 65
danqing
  • 3,348
  • 2
  • 27
  • 43
  • Make sure you extended required delegates in your class. Yeah, searchbar shows below the navbar but its inside the navbar.. like native setting app. – dahiya_boy Apr 04 '19 at 05:00
  • @dahiya_boy thanks I did extend the delegates. And yes technically it's inside the navbar - I want it to look like Instagram or Twitter, i.e. it's one row (44pt) and there's just the search bar. – danqing Apr 04 '19 at 05:08
  • Please add your expected screen image and what you getting right now.. – dahiya_boy Apr 04 '19 at 05:10
  • I want something similar to what's in https://stackoverflow.com/questions/26726520/get-search-bar-in-navigation-bar-in-swift. My main issue though is that no delegate methods are being triggered. – danqing Apr 04 '19 at 05:14

3 Answers3

1

Just define UISearchController as property then everything working fine.

I have tested below in the sample project.

  class ViewControllerName: UIViewController{
       let searchController = UISearchController(searchResultsController: nil)

        override func viewDidLoad() {
            super.viewDidLoad()
            let search = UISearchController(searchResultsController: nil)
            self.navigationItem.searchController = search
            self.navigationItem.searchController!.searchBar.delegate = self
            self.navigationItem.searchController!.searchResultsUpdater = self
            self.navigationItem.searchController?.searchBar.showsCancelButton = true
        }

       func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
            print("Called")
        }

        func updateSearchResults(for searchController: UISearchController) {
            print("Called")
        }
    }

Hope it will work for you.

Hitesh Surani
  • 12,733
  • 6
  • 54
  • 65
  • There are predefines rules for delegate e.g If you adding something programmatically in View or ViewController and you want to assign any delegate then define as property because sometimes facing the issue like you, For rest of case it will work. Glad to hear worked for you. Happy coding – Hitesh Surani Apr 04 '19 at 06:18
  • Can you please change your question title 'Unable to put UISearchController's search bar into navigation bar'(e.g Delegate not called or else) I think it is not appropriate. The proper title will others too. – Hitesh Surani Apr 04 '19 at 06:20
  • It's actually a proper title. As I described in the question, if I don't put the search bar in the nav bar it works fine. Only when I put it into the navbar like that did it stop working. Thanks again! – danqing Apr 04 '19 at 06:30
0

I have tried this code and everything working prop

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UISearchResultsUpdating {


@IBOutlet weak var tblView: UITableView!


override func viewDidLoad() {
    super.viewDidLoad()
    :
    :

    let search = UISearchController(searchResultsController: nil)
    self.navigationItem.searchController = search
    self.navigationItem.searchController!.searchBar.delegate = self
    self.navigationItem.searchController!.searchResultsUpdater = self
    self.navigationItem.searchController?.searchBar.showsCancelButton = true

    :
    :
}

Tested below delegates and both are called as expected.

func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
    print("search end editing.")
}

func updateSearchResults(for searchController: UISearchController) {
    print("update search results ... called here")
}

UI:

enter image description here

dahiya_boy
  • 9,298
  • 1
  • 30
  • 51
  • Thanks! This is what I wanted to avoid - as you can see there's an "invisible navbar" above the search bar if done this way. The above answer worked for me. – danqing Apr 04 '19 at 06:31
0

Call this

self.navigationItem.titleView = searchController.searchBar

from viewWillAppear(), not from viewDidLoad(). And delegates methods works fine.

Yuriy
  • 23
  • 1
  • 6