You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用带自定义单元格的独立视图控制器展示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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:27:01