Search code examples
iosswiftuicollectionviewuicollectionviewcelluicollectionviewflowlayout

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


I am trying to implement a UICollectionViewCell that includes a UITextView that resizes during runtime as the amount of text a user enters in it increases, as well as moves the cells above it up or down based on the size of the text box. (This UICollectionView is implemented with the UICollectionViewDelegateFlowLayout)

I am able to resize the actual cell during runtime while the user is entering text into the cell through the textViewDidChange() method of the UITextViewDelegate. However this does not change the position of the other cells, as collectionView(\_:layout:sizeForItemAt:) is not called immediately. I am able to trigger collectionView(_:layout:sizeForItemAt:) if I call reloadData() within the UICollectionView class, which repositions the other cells relative to the one of interest, but the problem with this is that this reloads the all the objects, and the keyboard that immediately closes.

Is there a way to trigger collectionView(_:layout:sizeForItemAt:) without calling reloadData()?

Another question that is getting at what I want to know is Resize CollectionView Cell during runtime without reloading but their question is not answered either.


Solution

  • I'm not sure what your triggering event is for resizing, but the easiest way to do this I can think of would be passing a weak reference to the collectionView to your collectionViewCell when you create it. Make sure it's weak because cells get created and destroyed all the time and you don't want to have a retain cycle.

    One approach might be to just use the didSet for bounds of the cell. I don't think this will be do anything when you initialize the cell, but whenever the bounds of an individual cell changes, you could call your method there. I haven't tested this approach, but I think it's a lazy, low-lift, minimal bookkeeping solution.

    Here's the "physics for poets" of what it would look like:

    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()
        }
    }