如何在UICollectionViewController(Swift 4)中实现UISearchBarController?
在UICollectionViewController中集成UISearchController的完整实现
我来帮你把这个搜索功能的实现补全并梳理清楚关键细节,结合你给出的代码片段,整理出可直接运行的完整方案:
1. 完整代码示例
import UIKit // 先假设你的RecommendArticles模型结构(如果实际结构不同,按需调整即可) struct RecommendArticles { let title: String // 可以添加其他属性,比如subtitle、imageURL等 } class FirstViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout, UISearchResultsUpdating { // 原始数据源:存放所有文章标题 var titles: [String] = [] // 原始模型数组 var card: [RecommendArticles]? // 搜索过滤后的数据源:实时更新并刷新列表 var searchArr: [String] = [] { didSet { self.collectionView?.reloadData() } } // 声明搜索控制器实例 private let searchController = UISearchController(searchResultsController: nil) override func viewDidLoad() { super.viewDidLoad() // 初始化搜索控制器 setupSearchController() // 模拟初始化原始数据(实际项目中替换为接口请求或本地数据) initOriginalData() } // MARK: - 初始化原始数据 private func initOriginalData() { card = [ RecommendArticles(title: "SwiftUI从入门到精通"), RecommendArticles(title: "UICollectionView布局实战"), RecommendArticles(title: "UISearchController最佳实践"), RecommendArticles(title: "iOS性能优化技巧") ] // 从模型数组中提取标题到titles数组 titles = card?.map { $0.title } ?? [] // 初始化搜索数组为全部数据 searchArr = titles } // MARK: - 配置搜索控制器 private func setupSearchController() { // 设置搜索结果更新代理为当前控制器 searchController.searchResultsUpdater = self // 搜索时是否隐藏导航栏(这里设置为false,保持导航栏可见) searchController.hidesNavigationBarDuringPresentation = false // 搜索时不模糊背景,让用户仍能看到下方的列表 searchController.obscuresBackgroundDuringPresentation = false // 设置搜索栏占位符文本 searchController.searchBar.placeholder = "搜索文章标题..." // 将搜索栏集成到导航栏 navigationItem.searchController = searchController // 确保搜索控制器的展示范围仅在当前控制器内,避免影响其他页面 definesPresentationContext = true } // MARK: - UISearchResultsUpdating 代理方法(搜索文本变化时触发) func updateSearchResults(for searchController: UISearchController) { guard let searchText = searchController.searchBar.text?.trimmingCharacters(in: .whitespacesAndNewlines), !searchText.isEmpty else { // 搜索框为空时,恢复显示全部数据 searchArr = titles return } // 执行过滤逻辑:忽略大小写匹配,提升用户体验 searchArr = titles.filter { $0.lowercased().contains(searchText.lowercased()) } } // MARK: - UICollectionView 数据源方法 override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { // 根据搜索状态返回对应数据源的数量 return searchController.isActive ? searchArr.count : titles.count } override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ArticleCell", for: indexPath) // 复用cell前清空旧内容(实际项目建议用自定义cell,这里为了演示简化) cell.contentView.subviews.forEach { $0.removeFromSuperview() } // 获取当前要显示的标题 let currentTitle = searchController.isActive ? searchArr[indexPath.item] : titles[indexPath.item] // 添加标签显示标题 let titleLabel = UILabel(frame: cell.contentView.bounds.inset(by: UIEdgeInsets(top: 8, left: 12, bottom: 8, right: 12))) titleLabel.text = currentTitle titleLabel.numberOfLines = 0 titleLabel.textColor = .black cell.contentView.addSubview(titleLabel) // 给cell加个边框,方便看效果 cell.layer.borderWidth = 1 cell.layer.borderColor = UIColor.lightGray.cgColor cell.layer.cornerRadius = 8 return cell } // MARK: - UICollectionViewDelegateFlowLayout 布局方法 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { // 设置cell宽度为屏幕宽度减左右边距,高度固定为80 return CGSize(width: collectionView.bounds.width - 24, height: 80) } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { // 设置section的内边距 return UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12) } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 注册cell(实际项目建议在viewDidLoad中注册) collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "ArticleCell") } }
2. 核心细节说明
- 数据源分离:用
titles存原始数据,searchArr存过滤后的数据,通过searchController.isActive判断当前使用哪个数据源,保证搜索和非搜索状态的内容正确切换。 - 搜索控制器配置:
setupSearchController方法里完成了所有基础配置,其中definesPresentationContext = true是关键,它能确保搜索控制器的弹窗不会渗透到其他控制器。 - 过滤逻辑优化:对搜索文本做了去除空格处理,并且用小写匹配,避免用户输入大小写导致搜索不到的问题;当搜索框清空时自动恢复全部数据。
- CollectionView适配:在数据源方法中根据搜索状态返回对应的数据量和内容,确保列表能实时响应搜索结果。
3. 进阶建议
- 使用模型数组作为搜索数据源:如果你的
RecommendArticles有更多属性,建议把searchArr改成[RecommendArticles]类型,这样可以在cell中展示更多信息(比如副标题、图片),而不仅仅是标题。 - 自定义UICollectionViewCell:实际项目中不要在
cellForItemAt里重复创建子视图,自定义cell能提升性能和代码可维护性。 - 添加搜索防抖:如果搜索逻辑比较复杂(比如网络请求搜索),可以添加防抖处理,避免用户输入时频繁触发搜索,提升性能。
内容的提问来源于stack exchange,提问作者Vincent
相关产品推荐
相关产品推荐

