How to place UISearchController to the navigationT

2020-03-31 04:55发布

问题:

I am new to Swift and wondering if there any possibilities to place UIsearchcontroller in navgationtitle and to hide and unhide uisearchcontroller by button that is located as navigationRightItem. I have seen many examples with placing the UISearchBar from Object library to the navigationTitle, but there is no example with the uisearchcontroller. Some even say that UISearch bar from object library has been deprecated from ios10 Swift. Please clarify the deprecation and why i should refrain from using UISearchBar from object library. And which one is the best practice to use for firebase tableview search. I would be glad if you could give with the code examples. Thank you in advance.

回答1:

UISearchBar

UISearchBar has not been deprecated. A UISearchBar is a UIView that you can place anywhere you want, including the navigation bar, but also in the middle of the screen if that’s what you want. You can do this programatically or you can use the Interface Builder to drag a search bar and place it inside one of your views.

Using UISearchBar

One way to implement search is to use a UISearchBar, put it in you navigationItem.titleView, and set your view controller to be the delegate of this search bar. When the user interacts with the search bar, your view controller is notified and you have to deal with the search logic in this same view controller. For example, you may need to detect whether the search is active to decide what data source to use for your table view - if the search is not active you show all items; if the search is active you show only a subset of items. Or maybe you want to show one layout for your main view and a different one for your search results. Again, you would have to deal with this logic in your view controller. This is where a UISearchController comes in handy!

Using UISearchController

A UISearchController is a UIViewController that provides you with a UISearchBar. A UISearchController is useful because it helps you present your search results in a new view controller, keeping your search logic separate from your main logic. To address a specific point in your question, keep in mind that the thing you put in your navigationItem.titleView is a UISearchBar, not a UISearchController. You can either create this UISearchBar yourself or you can create a UISearchController and use its search bar instead (searchController.searchBar).

Placing UISearchBar in navigationItem.titleView VS using navigationItem.searchController property

Placing your UISearchBar in navigationItem.titleView is a common pattern used in multiple apps. However, with iOS 11, Apple introduced the navigationItem.searchController property. There is nothing deprecated here but when it comes to using search bars in navigation bars, it seems Apple would prefer us to do it like this.

Below is an example of how this might work.

Your main view controller:

class HomeViewController: UIViewController {
   (…)

    override func viewDidLoad() {
        (…)

        // Get the view controller that will be used to present search results.
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        guard let languagesSearchResultsViewController = storyboard.instantiateViewController(withIdentifier: "LanguagesSearchResultsViewController") as? LanguagesSearchResultsViewController else { return }

        // Create a search controller and initialize it with the view controller that will be used to show the search results
        let searchController = UISearchController(searchResultsController: languagesSearchResultsViewController)

        // The searchResultsUpdater is the object that will be notified when the user performs a search.
        // I'm setting it to be the view controller that will present the results but is doesn't have to be.
        searchController.searchResultsUpdater = languagesSearchResultsViewController

        // Set the searchController property in the navigationItem and a search bar will automagically appear in the navigation bar, below the title.
        navigationItem.searchController = searchController
        definesPresentationContext = true

        (…)        
    }
}

The view controller that you’ll use to present the search results:

class LanguagesSearchResultsViewController: UIViewController {

    // MARK: - Properties

    // Complete list of items to search. If you're doing a network request for your search term then you don't need this.
    let languages = ["Mandarin Chinese", "English", "Hindustani", "Spanish", "Arabic", "Malay", "Russian", "Bengali", "Portuguese", "French", "Hausa", "Punjabi", "German", "Japanese", "Persian", "Swahili", "Telugu", "Javanese", "Wu Chinese", "Korean"]

    // The data source for your search results
    var searchResults: [String] = []

    // MARK: - IBOutlets

    @IBOutlet weak var tableView: UITableView!

    // MARK: - UIViewController methods

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.dataSource = self
    }

   (…)
}

// MARK: - UISearchResultsUpdating

extension LanguagesSearchResultsViewController: UISearchResultsUpdating {
    func updateSearchResults(for searchController: UISearchController) {
        guard let searchText = searchController.searchBar.text else { return }
        searchResults = languages.filter { $0.contains(searchText) }
        tableView.reloadData()
    }
}

// MARK: - UITableViewDataSource

extension LanguagesSearchResultsViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return searchResults.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "LanguageTableViewCell") as? LanguageTableViewCell else { return UITableViewCell() }

        let language = searchResults[indexPath.row]

        cell.languageNameLabel.text = language
        return cell
    }
}

If you still want a search bar in your titleView with the show/hide behaviour you describe, you will need something a bit more custom, with or without using a UISearchController. There are already many answers to other questions that may help you do that. Hopefully this will have helped clarify your options.