3
votes

I have a UITableViewController which has a UISearchController in the navigation bar. I use a different UIViewController as the results Controller. When I tap the search bar and start typing, the results controller is presented as below.

enter image description here

However, I want to show the results controller as soon as the User taps the search bar with some suggestions, like the native Messages app.

The option is available in iOS 13+, by setting showsSearchResultsController to true in presentSearchController method of UISearchControllerDelegate. How to implement the same for iOS 11+?

Full code:

import UIKit

class SearchViewController: UITableViewController {

    lazy var resultsController = ResultsVC()
    lazy var searchController = UISearchController(searchResultsController: resultsController)

    override func viewDidLoad() {
        super.viewDidLoad()

        configureSearchController()

        navigationItem.largeTitleDisplayMode = .always
        navigationController?.navigationBar.prefersLargeTitles = true
        navigationItem.title = "Search VC"
    }

    func configureSearchController() {
        navigationItem.searchController = searchController
        navigationItem.hidesSearchBarWhenScrolling = true
        searchController.obscuresBackgroundDuringPresentation = false
        searchController.hidesNavigationBarDuringPresentation = true
        searchController.searchResultsUpdater = resultsController
        searchController.delegate = self
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        navigationController?.pushViewController(SearchViewController(), animated: true)
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 50
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        cell.textLabel?.text = "Search cell"
        return cell
    }
}

extension SearchViewController: UISearchControllerDelegate {
    func presentSearchController(_ searchController: UISearchController) {
        if #available(iOS 13.0, *) {
            searchController.showsSearchResultsController = true
        } else {
            // TODO:- show results controller
        }

        resultsController.showingSuggestions = true
    }
}

class ResultsVC: UITableViewController {

    lazy var showingSuggestions = false

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        navigationController?.pushViewController(SearchViewController(), animated: true)
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 50
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        cell.textLabel?.text = showingSuggestions ? "Suggestion cell" : "Result cell"
        return cell
    }
}

extension ResultsVC: UISearchResultsUpdating {
    func updateSearchResults(for searchController: UISearchController) {
        if let searchText = searchController.searchBar.text,
            !searchText.isEmpty {
            showingSuggestions = false
        } else {
            showingSuggestions = true
        }
        tableView.reloadData()
    }
}
1

1 Answers

0
votes

I am not sure this is a good way, but you can do as below

func updateSearchResults(for searchController: UISearchController) {
    searchController.searchResultsController?.view.isHidden = false
}

Initially, result controller view is hidden. You can make it visible by setting its hidden property false.

This works for me.