You need to enable JavaScript to run this app. Swift中在UITableViewController内显示UICollectionView的问题求助
优惠活动
大模型
产品
解决方案
定价
更多

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。

具体修复步骤

  1. 优化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
}
  1. 修正搜索状态切换逻辑:
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()
}
  1. 补充基础配置修复:
  • 在viewDidLoad末尾添加tableView.isHidden = true,初始进入页面默认显示collectionView
  • 修正searchBar:textDidChange:中的笔误,将filteredItem = item.filter改为filteredItem = item1.filter
  • 在fetchItem2的异步回调完成后调用collectionView.reloadData()刷新列表

内容的提问来源于stack exchange,提问作者swiftcrackhead1

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 05:45:01