Swift中在UITableViewController内显示UICollectionView的问题求助
问题描述
需求为在UITableViewController类中显示UICollectionView:页面配置了UISearchBar用于筛选条目,期望在取消搜索收起searchbar时显示collectionView。多日尝试在多个位置调用configureCollectionView方法均未生效,已注册的所有Cell在其他控制器中均可正常运行。
相关代码
private let reuseIdentifier = "SearchThisCell" class SearchController: UITableViewController, UISearchBarDelegate, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { var item1 = [Item1]() var searchbar = UISearchBar() var filteredItem = [Item1]() var inSearchMode = false var collectionView: UICollectionView! var collectionViewEnabled = true var item2 = [Item2]() override func viewDidLoad() { super.viewDidLoad() // register cell classes tableView.register(SearchThisCell.self, forCellReuseIdentifier: reuseIdentifier) tableView.separatorInset = UIEdgeInsets(top: 0, left: 75, bottom: 0, right: 75) tableView.separatorStyle = .none configureSearchBar() configureCollectionView() fetchItem1() fetchItem2() } override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 70 } override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if inSearchMode { return filteredItem.count } else { return item1.count } } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { var item: Item1! if inSearchMode { item = filteredItem[indexPath.row] } else { item = item1[indexPath.row] } let itemProfileVC = ItemProfileController(collectionViewLayout: UICollectionViewFlowLayout()) itemProfileVC.item = item navigationController?.pushViewController(itemProfileVC, animated: true) } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath) as! SearchThisCell var item: Item1! if inSearchMode { item = filteredItem[indexPath.row] } else { item = item1[indexPath.row] } cell.item = item1 return cell } func configureCollectionView() { let layout = UICollectionViewFlowLayout() layout.scrollDirection = .vertical let frame = CGRect(x: 50, y: 50, width: view.frame.width, height: view.frame.height - (tabBarController?.tabBar.frame.height)! - (navigationController?.navigationBar.frame.height)!) collectionView = UICollectionView(frame: frame, collectionViewLayout: layout) collectionView.delegate = self collectionView.dataSource = self collectionView.alwaysBounceVertical = true collectionView.backgroundColor = .white collectionView.register(SearchThatCell.self, forCellWithReuseIdentifier: "SearchThatCell") tableView.addSubview(collectionView) tableView.separatorColor = .clear } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { return 1 } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { return 1 } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let width = (view.frame.width - 2) / 3 return CGSize(width: width, height: width) } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return item2.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SearchThatCell", for: indexPath) as! SearchThatCell cell.that = item2[indexPath.item] return cell } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { let overviewVC = OverviewController(collectionViewLayout: UICollectionViewFlowLayout()) overviewVC.viewSingleItem = true overviewVC.that = item2[indexPath.item] navigationController?.pushViewController(overviewVC, animated: true) } func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) { searchbar.showsCancelButton = true collectionView.isHidden = false collectionViewEnabled = true } func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { let searchText = searchText.lowercased() if searchText.isEmpty || searchText == " " { inSearchMode = false tableView.reloadData() } else { inSearchMode = true filteredItem = item.filter({ (item) in return item.itemname.contains(searchText) }) tableView.isHidden = false tableView.reloadData() } } func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { searchbar.endEditing(true) searchbar.showsCancelButton = false inSearchMode = false searchbar.text = nil collectionViewEnabled = true configureCollectionView() tableView.isHidden = true tableView.reloadData() } }
注:后续为已验证可正常运行的数据拉取方法
修复方案
核心问题点
- 重复创建collectionView:
searchBarCancelButtonClicked中重复调用configureCollectionView,每次都会新建实例添加到tableView上,造成视图层级冗余,且frame硬编码时机错误,viewDidLoad阶段导航栏、tabBar尺寸还未完全确定,计算结果偏差大。 - 显示逻辑错误:搜索状态切换时collectionView和tableView的显隐逻辑完全相反,初始状态未做显隐处理。
- 数据刷新遗漏:
item2数据拉取完成后未调用collectionView.reloadData(),导致collectionView无内容渲染。 - 代码笔误:
searchBar:textDidChange:中filteredItem = item.filter的item变量不存在,应为item1。
具体修复步骤
- 优化
configureCollectionView方法,仅在viewDidLoad调用一次,使用自动布局代替硬编码frame,初始状态隐藏:
func configureCollectionView() { let layout = UICollectionViewFlowLayout() layout.scrollDirection = .vertical collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) collectionView.translatesAutoresizingMaskIntoConstraints = false collectionView.delegate = self collectionView.dataSource = self collectionView.alwaysBounceVertical = true collectionView.backgroundColor = .white collectionView.register(SearchThatCell.self, forCellWithReuseIdentifier: "SearchThatCell") collectionView.isHidden = true // 直接添加到根视图,避免和tableView滚动冲突 view.addSubview(collectionView) NSLayoutConstraint.activate([ collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor), collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) ]) tableView.separatorColor = .clear }
- 修正搜索状态切换逻辑:
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) { searchbar.showsCancelButton = true // 进入搜索状态显示tableView,隐藏collectionView collectionView.isHidden = true tableView.isHidden = false collectionViewEnabled = false } func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { searchbar.endEditing(true) searchbar.showsCancelButton = false inSearchMode = false searchbar.text = nil collectionViewEnabled = true // 取消搜索显示collectionView,隐藏tableView tableView.isHidden = true collectionView.isHidden = false collectionView.reloadData() tableView.reloadData() }
- 补充基础配置修复:
- 在
viewDidLoad末尾添加tableView.isHidden = true,初始进入页面默认显示collectionView - 修正
searchBar:textDidChange:中的笔误,将filteredItem = item.filter改为filteredItem = item1.filter - 在
fetchItem2的异步回调完成后调用collectionView.reloadData()刷新列表
内容的提问来源于stack exchange,提问作者swiftcrackhead1
相关产品推荐
相关产品推荐

