2

I have a UICollectionViewController which generates cells with a random color for testing purposes. Now that the UICollectionViewController is embedded in a UIScrollView, I want the scrollView to be the same size as it's contentSize.

I made a subclass of UICollectionView, implemented intrinsicContentSize method, and set the UICollectionView's class to my custom class in IB. However intrinsicContentSize never gets called. I have the exact same setup with an UITableView and there it works flawlessly.

Any ideas on this?

- (CGSize)intrinsicContentSize {
    [self layoutIfNeeded];
    return CGSizeMake(UIViewNoIntrinsicMetric, self.contentSize.height);
}
Mirko Catalano
  • 3,850
  • 2
  • 26
  • 39
Ben Lime
  • 493
  • 6
  • 17

3 Answers3

14

The correct answer is to do something like this

- (CGSize)intrinsicContentSize
{
    return self.collectionViewLayout.collectionViewContentSize;
}

And call -invalidateContentSize whenever you think it needs to change (after reloadData for example).

In Interface Builder you may need to set placeholder intrinsic size constraints to avoid errors.

This subclassing and overriding of -intrinsicContentSize is useful if you want to grow a collection view's frame until it is constrained by a sibling or parent view

Marc Etcheverry
  • 1,010
  • 1
  • 10
  • 15
1

I'm not sure why it's happening. Here's another solution to this problem. Set up a height constraint on UICollectionView object. Then set its constant to be equal to self.collectionView.contentSize.height. I use a similar approach in my app, though I've got UITextView instead of UICollectionView.

UPDATE: I've found a way to do this with intrinsicContentSize: UITextView in UIScrollView using auto layout

Community
  • 1
  • 1
Arek Holko
  • 8,966
  • 4
  • 28
  • 46
  • That's the workaround I'm using right now. But anyway I think it would be a 'cleaner' way to use `intrinsicContentSize`. I'll wait if anybody has an idea, otherwise I'll accept your answer. – Ben Lime Oct 15 '13 at 09:59
  • @BenLime: I've just made it work in my project. Can you see what happens when you set intrinsic size in IB to `Placeholder`: http://dl.dropboxusercontent.com/u/5184129/Screenshots/4p0p.png ? – Arek Holko Oct 15 '13 at 10:52
  • Still no luck. Tried the `Placeholder` thing in an extra project but I'm experiencing the same behaviour. Anything else you did? – Ben Lime Oct 15 '13 at 12:47
  • https://github.com/fastred/UICollectionView-intrinsicContentSize here's how I did it. `intrinsicContentSize:` isn't called on rotation, so it may be a wrong way of doing this in the end. – Arek Holko Oct 15 '13 at 13:19
  • Thanks. I think I will go with the height constraint mentioned above. – Ben Lime Oct 15 '13 at 15:59
-1

Use this class to make UICollectionView update its intrinsic content size every time the content is changed.

class AutosizedCollectionView: UICollectionView {
    override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
        super.init(frame: frame, collectionViewLayout: layout)
        registerObserver()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        registerObserver()
    }

    deinit {
        unregisterObserver()
    }

    override var intrinsicContentSize: CGSize {
        return contentSize
    }

    private func registerObserver() {
        addObserver(self, forKeyPath: #keyPath(UICollectionView.contentSize), options: [], context: nil)
    }

    private func unregisterObserver() {
        removeObserver(self, forKeyPath: #keyPath(UICollectionView.contentSize))
    }

    override func observeValue(forKeyPath keyPath: String?,
                               of object: Any?,
                               change: [NSKeyValueChangeKey : Any]?,
                               context: UnsafeMutableRawPointer?)
    {
        if keyPath == #keyPath(UICollectionView.contentSize) {
            invalidateIntrinsicContentSize()
        }
    }
}

Though, you should understand that if you embed it into another scroll view, cell recycling will not work. The most appreciated way to deal with nested collection view is described here.