1

Please note that this is NOT a question about self sizing UICollectionViewCell.

Is it possible to create self sizing UICollectionView (with UICollectionViewFlowLayout) size of which depends on cells inside it?

I have a collection view with variable number of cells. I would like to constrain width of the collection view and then allow it to expand vertically depending on quantity of cells.

This question is similar to this one CollectionView dynamic height with Swift 3 in iOS but I have multiple cells per row.

Bonus points, if one could still use self sizing cells inside of collection view but it is ok if collection view delegate provides cell sizes.

iur
  • 1,886
  • 2
  • 8
  • 28

2 Answers2

1

I don't have enough reputation to comment, but I think this is the answer that you are looking for. Code below:

 class DynamicCollectionView: UICollectionView {
     override func layoutSubviews() {
         super.layoutSubviews()
         if bounds.size != intrinsicContentSize() {
             invalidateIntrinsicContentSize()
         }
     }

     override func intrinsicContentSize() -> CGSize {
         return self.contentSize
     }
 }
Max von Hippel
  • 2,468
  • 2
  • 28
  • 41
0

@Michal Gorzalczany's answer led me to this answer (for my specific case):

  1. Subclass UICollectionView

    class DynamicCollectionView : UICollectionView {
    
        weak var layoutResp : LayoutResponder?
    
        override func invalidateIntrinsicContentSize() {
            super.invalidateIntrinsicContentSize()
            self.layoutResp?.updateLayout()
        }
    
        override var intrinsicContentSize : CGSize {
            return self.contentSize
        }
    
        override var contentSize: CGSize {
            get { return super.contentSize }
    
            set {
                super.contentSize = newValue
                self.invalidateIntrinsicContentSize()
            }
        }
    }
    
  2. Protocol LayoutResponder should be adopted by the view which deals on a high level with layout of collection view (I have a relatively complex layout).

    protocol LayoutResponder : class {
        func updateLayout()
    }
    
    
    extension RespView : LayoutResponder {
        func updateLayout() {
            self.layoutResp?.setNeedsLayout()
            self.layoutResp?.layoutIfNeeded()
        }
    }
    

    In my case I actually forward updateLayout() even further up the chain.

I guess for simpler layouts you can skip step 2 alltogether.

This is in my opinion is a bit "hacky" so if someone has a better approach I would appreciate if you share.

iur
  • 1,886
  • 2
  • 8
  • 28