UICollectionView not calling intrinsicContentSize

2019-04-02 05:21发布

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

3条回答
爷、活的狠高调
2楼-- · 2019-04-02 05:59

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.

查看更多
放我归山
3楼-- · 2019-04-02 06:10

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 is subclassing and overriding of -intrinsicContentSize useful if you want to grow a collection view's frame until it is constrained by a sibling or parent view

查看更多
来,给爷笑一个
4楼-- · 2019-04-02 06:12

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

查看更多
登录 后发表回答