在不调用 reloadData() 的情况下使用 collectionView(_:layout:sizeForItemAt:) 调整 UICollectionView 单元格的大小

Resizing UICollectionView cells with collectionView(_:layout:sizeForItemAt:) without calling reloadData()

我正在尝试实现一个 UICollectionViewCell,其中包含一个 UITextView,该 UITextView 在运行时随着用户在其中输入的文本量的增加而调整大小,并将其上方的单元格向上移动或根据文本框的大小向下。 (这个 UICollectionView 是用 UICollectionViewDelegateFlowLayout 实现的)

当用户通过 UITextViewDelegatetextViewDidChange() 方法在单元格中输入文本时,我能够在运行时调整实际单元格的大小。然而,这不会改变其他单元格的位置,因为 collectionView(\_:layout:sizeForItemAt:) 不会立即被调用。如果我在 UICollectionView class 中调用 reloadData(),我能够触发 collectionView(_:layout:sizeForItemAt:),这会相对于感兴趣的单元格重新定位其他单元格,但问题是这是重新加载所有对象,以及立即关闭的键盘。

有没有办法在不调用 reloadData() 的情况下触发 collectionView(_:layout:sizeForItemAt:)

另一个我想知道的问题是 Resize CollectionView Cell during runtime without reloading 但他们的问题也没有得到回答。

我不确定调整大小的触发事件是什么,但我能想到的最简单的方法是将 weak 引用传递给创建它时将 collectionView 添加到您的 collectionViewCell 中。确保它很弱,因为单元格一直在创建和销毁,你不希望有一个保留周期。

一种方法可能是只使用 didSet 作为单元格的 bounds。我不认为这会在您初始化单元格时执行任何操作,但只要单个单元格的边界发生变化,您就可以在那里调用您的方法。我没有测试过这种方法,但我认为这是一种懒惰的、低提升的、最小的簿记解决方案。

这是 "physics for poets" 的样子:

class YourCell: UICollectionViewCell {

    weak var collectionView: UICollectionView?

    // Whatever other stuff you need on your cell

    override var bounds: CGRect {
        didSet {
            // Whenever the bounds get set, the collectionView's layout will be invalidated.
            invalidateCollectionViewLayout()
        }
    }

    private func invalidateCollectionViewLayout() {
        guard let collectionView = collectionView else { return }
        collectionView.collectionViewLayout.invalidateLayout()
    }
}