自动调整大小的CollectionView在自动调整大小的TableViewCell中

3
我花了几周的时间尝试让这个工作,并查看了许多不同的建议,包括这里、苹果开发者论坛、谷歌等,但仍然很困惑。任何帮助都将不胜感激。
我有一个包含TableView的ViewController。它不是全屏tableView。
tableView是由自定义TableViewCell构建的,每个TableViewCell都包含一个CollectionView。我的问题是,自适应大小的collectionView和tableView行似乎无法正常工作。我在网上找到了一些选项,但它们只能部分地解决问题。
以下是它最初运行时的情况:

enter image description here

我在这里放了一个项目文件的链接,这样比把代码复制到这里更容易: https://www.dropbox.com/sh/7a2dquvxg62aylt/AACK_TjDxT9eOShZaKi7vLYga?dl=0 有些在线的“解决方法”并不适用于所有情况——例如,如果您点击CollectionView中的一个按钮,它会被删除,collectionView(以及随后的TableView)应该调整大小,但是我无法使其始终有效。
我尝试过的一些解决方案: 使用Auto Layout自动调整大小的UICollectionView单元格 UITableView中的UICollectionView——动态高度?

基于动态集合视图的UITableView的动态高度

包含UICollectionView的自动调整UITableViewCell

非常感谢您的帮助。


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

2

我找出了问题所在。有几个地方需要修复:

  1. You need to set an estimated row height (with an actual value) and set the row height as automatic. You did the opposite. So please, replace your setupTableView function with this one below. Also, yo need to set the delegate which you didn't do. So make sure you add UITableViewDelegate next to your class name, and assign it inside of setupTableView() like I did below.

    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()
    }
    
  2. Inside cellForRowAt, add layoutIfNeeded to make sure the cells are auto sized properly:

    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
        }
    }
    
  3. Your CustomCollectionView needs to subclass UICollectionViewDelegateFlowLayout.

  4. Make sure you assign your configuredCollectionViewLayout variable to your collectionView:

    func setupCollectionView() {
        backgroundColor = .systemPink
        isScrollEnabled = false
        register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: CustomCollectionViewCell.cellIdentifier)
        dataSource = self
        self.collectionViewLayout = configuredCollectionViewFlowLayout
    }
    
  5. Finally, add these 3 overrides to make your collectionView auto size based on its content (inside 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()
                }
            }
        }
    }
}

你是正确的。只有第一个单元格表现出了奇怪的行为,但我已经找到了解决方法——随后的单元格都可以正常工作。我已经更新了我的答案。在setupTableView()中,为tableView调用layoutIfNeeded()。 - rs7
对于您提到的第二个问题,您可以简单地定义一个协议,让您的视图控制器采用,并且每次单击按钮时,通过tableView.beginUpdates() tableView.endUpdates()触发tableView更新。 - rs7
谢谢。已更新并测试。你是正确的,当你移除令牌(通过点击它们)时,collectionView现在会调整大小,但tableViewCell不会随着其内容(即collectionView)的更改而更新。 - Anthony
我已经更新了我的答案,向您展示如何在点击令牌后触发单元格布局更新。 - rs7
谢谢。我回复后看到了这个。我已经包含了建议,它部分地起作用了。1. 视图最初被加载并正确显示,尽管xCode会抛出布局错误 - 有什么建议吗?2. 使用委托方法来更新tableview部分起作用,但最终我将其添加到customCollectionView的完成块中 - 谢谢! - Anthony
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接