Self Sizing CollectionView 在 Self Sizing TableViewCell 内

Posted

技术标签:

【中文标题】Self Sizing CollectionView 在 Self Sizing TableViewCell 内【英文标题】:Self Sizing CollectionView inside a Self Sizing TableViewCell 【发布时间】:2020-06-21 16:07:59 【问题描述】:

我花了数周的时间试图让它发挥作用,并在此处、Apple 开发者论坛、Google 等上查看了许多不同的建议,但我仍在努力解决问题。任何帮助将不胜感激。

我有一个包含 TableView 的 ViewController。不是全屏tableView。

tableView 是用 customTableViewCells 构建的,每个都有一个 CollectionView。我遇到的问题是自调整collectionView 和自调整tableView 行似乎不起作用。我在网上找到了一些选项,但它们似乎只是部分有效。

这是我最初运行时得到的:

我包含一个指向项目文件的链接,因为这可能比将代码复制到此处更容易: https://www.dropbox.com/sh/7a2dquvxg62aylt/AACK_TjDxT9eOShZaKi7vLYga?dl=0

某些在线“解决方法”并非在所有情况下都有效 - 例如如果您点击 CollectionView 中的一个按钮,它会被移除,并且 collectionView(以及随后的 TableView)应该调整大小,但我还是不能让它始终如一地工作。

我尝试过的一些解决方案:

UICollectionView Self Sizing Cells with Auto Layout

UICollectionView inside a UITableViewCell -- dynamic height?

Dynamic height for a UITableView based on a dynamic collection view

Auto-sizing UITableViewCell which contains UICollectionView

任何帮助将不胜感激。

【问题讨论】:

我认为为那些不想浏览整个项目的人添加相关代码是个好主意。 注意@rs7 - 我实际上创建了一个简化的 Xcode 项目文件,它只有这个问题/问题的 coe。我认为当他们没有查看完整的互连代码时,引用其他一些解决方案是问题的一部分。抱歉,我试图提供帮助而不是阻碍。 完全不用担心@Anthony。这只是一个建议而不是批评。 【参考方案1】:

我知道出了什么问题。有几件事需要解决:

    您需要设置估计的行高(带有实际值)并将行高设置为自动。你反其道而行之。所以请用下面的这个替换你的 setupTableView 函数。另外,你需要设置你没有做的委托。因此,请确保在类名旁边添加 UITableViewDelegate,并像我在下面所做的那样在 setupTableView() 中分配它。

    func setupTableView() 
        view.addSubview(tempTableView)
        NSLayoutConstraint.activate([
            tempTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tempTableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 200),
            tempTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            tempTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -200)
        ])
        tempTableView.rowHeight = UITableView.automaticDimension
        tempTableView.estimatedRowHeight = 90
        tempTableView.register(CustomTableViewCell.self, forCellReuseIdentifier: CustomTableViewCell.cellIdentifier)
        tempTableView.dataSource = self
        tempTableView.delegate = self
        tempTableView.translatesAutoresizingMaskIntoConstraints = false
        tempTableView.layoutIfNeeded()
    
    

    在 cellForRowAt 中,添加 layoutIfNeeded 以确保单元格自动调整大小:

    extension ViewController: UITableViewDataSource, UITableViewDelegate 
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
            2
        
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
            let cell = tempTableView.dequeueReusableCell(withIdentifier: CustomTableViewCell.cellIdentifier) as! CustomTableViewCell
            cell.layoutIfNeeded()
            return cell
        
    
    

    您的 CustomCollectionView 需要继承 UICollectionViewDelegateFlowLayout。

    确保将您配置的CollectionViewLayout 变量分配给您的collectionView:

    func setupCollectionView() 
        backgroundColor = .systemPink
        isScrollEnabled = false
        register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: CustomCollectionViewCell.cellIdentifier)
        dataSource = self
        self.collectionViewLayout = configuredCollectionViewFlowLayout
    
    

    最后,添加这 3 个覆盖以使您的 collectionView 根据其内容自动调整大小(在 CustomCollectionView 内):

    override var intrinsicContentSize: CGSize 
         self.layoutIfNeeded()
         return self.contentSize
     
    
     override var contentSize: CGSize 
         didSet
             self.invalidateIntrinsicContentSize()
         
     
    
     override func reloadData() 
         super.reloadData()
         self.invalidateIntrinsicContentSize()
     
    

这是在单击按钮时触发单元格重绘的方法。我没有使用协议,但请这样做,这只是向您展示这个想法:

func tokenTapped(withTitle title: String) 
    guard let indexOfItemToRemove = tokens.sampleData.firstIndex(where: $0.name == title) else  return 
    tokens.sampleData.remove(at: indexOfItemToRemove)
    DispatchQueue.main.async 
        self.performBatchUpdates(
            self.deleteItems(at: [IndexPath(item: indexOfItemToRemove, section: 0)])
        )  (true) in
            if let tableView = self.superview?.superview?.superview as? UITableView 
                print("tableview updates")
                tableView.beginUpdates()
                tableView.endUpdates()
                DispatchQueue.main.async 
                    tableView.layoutIfNeeded()
                
            
        
    

【讨论】:

谢谢,但我刚试过,它不适合我。虽然现在 collectionView 的大小变大了,但它的高度比内容大,所以底部有额外的空间。此外,当用户点击令牌按钮时,collectionView 和 tableViewCell 都不会调整大小,它们会从 collectionView 中删除。 你是对的。只有第一个单元格显示出一种奇怪的行为,尽管我找到了解决办法——后续单元格工作得很好。我已经更新了我的答案。在 setupTableView() 中,为 tableView 调用 layoutIfNeeded()。 对于您提到的第二个问题,您可以简单地定义您的 viewController 采用的协议,每次单击按钮时,您都会通过 tableView.beginUpdates() tableView.endUpdates() 触发 tableView 更新。 谢谢。对此进行了更新和测试。你是对的,当你删除令牌(通过点击它们)时,collectionView 现在正在调整大小,但是 tableViewCell 没有随着它的内容(即 collectionView)的变化而更新。 我再次更新了我的答案,向您展示如何在点击令牌后触发单元格布局更新。

以上是关于Self Sizing CollectionView 在 Self Sizing TableViewCell 内的主要内容,如果未能解决你的问题,请参考以下文章

Self Sizing Cells使UITableView跳跃

Self Sizing Cells 使 UITableView 跳跃

iOS 8 上的 UICollectionView self-sizing-cell 将与 UIDynamic flowLayout 和重复调用 _updateVisibleCellsNow 一起崩溃

iOS:通过Self-Sizing Cells新特性自动计算cell的高度

使用 .xib 设计 Self-Sizing UITableViewCell,单元格不会在界面生成器中自行调整

iOS小技能:解决TableVIew刷新数据带来的界面跳动问题