如何用带自定义单元格的独立视图控制器展示UISearchController搜索结果
配置UISearchController实现自定义搜索结果页面
这种拆分两个视图控制器来处理搜索的方案在iOS开发里挺常见的——主控制器管搜索配置,结果控制器负责自定义列表展示,既能把逻辑拆解开,也方便后续单独调整UI。下面结合你的场景,把CityViewController里的UISearchController配置代码补全并优化,顺便附上结果控制器的核心实现:
import UIKit class CityViewController: UIViewController { // 声明搜索控制器实例 var searchController: UISearchController? // 用来承载搜索栏的容器视图(适配不同布局场景) private let searchBarContainer = UIView() override func viewDidLoad() { super.viewDidLoad() setupSearchController() setupSearchBarLayout() } private func setupSearchController() { // 初始化自定义的搜索结果视图控制器 let citySearchVC = CitySearchViewController() // 创建搜索控制器并关联结果VC searchController = UISearchController(searchResultsController: citySearchVC) guard let searchController = searchController else { return } // 核心配置项 searchController.searchResultsUpdater = self // 监听搜索文本变化 searchController.obscuresBackgroundDuringPresentation = false // 搜索时不模糊背景 searchController.searchBar.placeholder = "搜索城市" searchController.searchBar.searchBarStyle = .minimal // 通过闭包实现两个VC的通信(避免强引用) citySearchVC.searchTextHandler = { [weak self] searchText in self?.updateSearchResults(for: searchText) } // 将搜索栏添加到容器视图 searchBarContainer.addSubview(searchController.searchBar) } private func setupSearchBarLayout() { // 用自动布局固定搜索栏位置 searchBarContainer.translatesAutoresizingMaskIntoConstraints = false view.addSubview(searchBarContainer) searchController?.searchBar.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ searchBarContainer.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), searchBarContainer.leadingAnchor.constraint(equalTo: view.leadingAnchor), searchBarContainer.trailingAnchor.constraint(equalTo: view.trailingAnchor), searchController!.searchBar.topAnchor.constraint(equalTo: searchBarContainer.topAnchor), searchController!.searchBar.leadingAnchor.constraint(equalTo: searchBarContainer.leadingAnchor), searchController!.searchBar.trailingAnchor.constraint(equalTo: searchBarContainer.trailingAnchor), searchController!.searchBar.bottomAnchor.constraint(equalTo: searchBarContainer.bottomAnchor) ]) } // 实际处理搜索逻辑的方法 private func updateSearchResults(for searchText: String?) { guard let searchText = searchText, !searchText.isEmpty else { // 搜索文本为空时重置结果 (searchController?.searchResultsController as? CitySearchViewController)?.resetResults() return } // 这里替换成你的真实搜索逻辑(比如过滤本地数据或请求接口) let filteredCities = ["北京", "上海", "广州", "深圳"].filter { $0.contains(searchText) } (searchController?.searchResultsController as? CitySearchViewController)?.updateResults(with: filteredCities) } } // 遵守UISearchResultsUpdating协议,接收搜索文本变化事件 extension CityViewController: UISearchResultsUpdating { func updateSearchResults(for searchController: UISearchController) { let searchText = searchController.searchBar.text (searchController.searchResultsController as? CitySearchViewController)?.handleSearchText(searchText) } } // 自定义搜索结果视图控制器(带自定义单元格) class CitySearchViewController: UIViewController { private let cellIdentifier = "CitySearchCell" private var cities: [String] = [] // 用于接收搜索文本的闭包(也可以用代理模式替代) var searchTextHandler: ((String?) -> Void)? // 自定义表格视图 private let tableView: UITableView = { let tableView = UITableView() tableView.translatesAutoresizingMaskIntoConstraints = false return tableView }() override func viewDidLoad() { super.viewDidLoad() setupTableView() } private func setupTableView() { view.addSubview(tableView) tableView.delegate = self tableView.dataSource = self // 注册自定义单元格 tableView.register(CitySearchCell.self, forCellReuseIdentifier: cellIdentifier) NSLayoutConstraint.activate([ tableView.topAnchor.constraint(equalTo: view.topAnchor), tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) } // 更新搜索结果的对外方法 func updateResults(with cities: [String]) { self.cities = cities tableView.reloadData() } // 重置结果的对外方法 func resetResults() { cities.removeAll() tableView.reloadData() } // 接收搜索文本的方法 func handleSearchText(_ text: String?) { searchTextHandler?(text) } } // 实现表格视图的代理和数据源 extension CitySearchViewController: UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return cities.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? CitySearchCell else { return UITableViewCell() } let city = cities[indexPath.row] cell.configure(with: city) return cell } } // 自定义单元格示例 class CitySearchCell: UITableViewCell { func configure(with cityName: String) { textLabel?.text = cityName // 这里可以添加自定义UI配置,比如图标、字体、颜色等 } }
核心要点说明
- 职责拆分:把搜索配置和结果展示分开,符合单一职责原则,后续修改搜索逻辑或结果UI时互不影响。
UISearchResultsUpdating协议:必须实现这个协议才能实时监听搜索栏的文本变化,触发结果更新。- 自定义结果页:因为需要自定义单元格,所以手动初始化
UITableView并配置代理、数据源,灵活度更高。 - 安全通信:用闭包传递搜索文本时加上
[weak self],避免循环引用导致内存泄漏。
内容的提问来源于stack exchange,提问作者Tigran Iskandaryan
相关产品推荐
相关产品推荐

