How to determine height of UICollectionView with FlowLayout

94,225

Solution 1

Whoa! For some reason, after hours of research, I now found a pretty easy answer to my question: I was completely searching in the wrong place, digging through all the documentation I could find on UICollectionView.

The simple and easy solution lies in the underlying layout: Just call collectionViewContentSize on your myCollectionView.collectionViewLayout property and you get the height and width of the content as CGSize. It's as easy as that.

Solution 2

In case you are using Auto layout, then you could create a subclass of UICollectionView

If you use the below the code then you don't have to specify any height constraints for the collection view as it would vary based on the contents of the collection view.

Given below is the implementation:

@interface DynamicCollectionView : UICollectionView

@end

@implementation DynamicCollectionView

- (void) layoutSubviews
{
    [super layoutSubviews];

    if (!CGSizeEqualToSize(self.bounds.size, [self intrinsicContentSize]))
    {
        [self invalidateIntrinsicContentSize];
    }
}

- (CGSize)intrinsicContentSize
{
    CGSize intrinsicContentSize = self.contentSize;

    return intrinsicContentSize;
}

@end

Solution 3

At viewDidAppear you can get it by:

float height = self.myCollectionView.collectionViewLayout.collectionViewContentSize.height;

Maybe when you reload data then need to calculate a new height with new data then you can get it by: add observer to listen when your CollectionView finished reload data at viewdidload:

[self.myCollectionView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld context:NULL];

Then add bellow function to get new height or do anything after collectionview finished reload:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary  *)change context:(void *)context
{
    //Whatever you do here when the reloadData finished
    float newHeight = self.myCollectionView.collectionViewLayout.collectionViewContentSize.height;    
}

And don't forget to remove observer:

[self.myCollectionView removeObserver:self forKeyPath:@"contentSize" context:NULL];

Solution 4

Swift 3 code for user1046037 answer

import UIKit

class DynamicCollectionView: UICollectionView {

    override func layoutSubviews() {
        super.layoutSubviews()
        if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
            self.invalidateIntrinsicContentSize()
        }

    }

    override var intrinsicContentSize: CGSize {
        return contentSize
    }

}

Solution 5

user1046037 answer in Swift...

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

    override func intrinsicContentSize() -> CGSize {
        return self.contentSize
    }
}
Share:
94,225
Jan Z.
Author by

Jan Z.

Since I got to know OOP in school, I've been a coding enthusiast. Sometimes working on private projects, sometimes doing some web design and web development for social or sustainable projects as well as non-profits, I improved my skills over the time. I started with Delphi, moved on to C#, did some work with PHP, HTML, CSS and Javascript, and had a good start with Java and the Android API. After that, I worked on an iOS project for about a 3/4 year, learning much about Objective C and Cocoa, and especially CoreData. Currently I work as a developer at Zollsoft. Even though I feel at home in the FOSS Linux and unixoid world, I'm open to almost any platform. In the future I'd like to learn more about machine learning and data mining.

Updated on January 15, 2020

Comments

  • Jan Z.
    Jan Z. over 4 years

    I've got an UICollectionView with an UICollectionViewFlowLayout, and i want to calculate its content size (for return in intrinsicContentSize needed for adjusting its height via AutoLayout).

    The problems is: Even if I have a fixed and equal height for all cells, I don't know how many "rows"/lines I have in the UICollectionView. I also can't determine that count by the number of items in my data source, since the cells representing the data items vary in width, so does consequently the number of items I have in one line of the UICollectionView.

    Since I couldn't find any hints on this topic in the official documentation and googling didn't bring me any further, any help and ideas would be appreciated very much.

  • Chris Chen
    Chris Chen over 10 years
    whoa, I wish UITableView has something similar
  • Chris Conover
    Chris Conover about 10 years
    Ignatus, @jbandi, Chris et al, can you expand on this? When I tested with a horizontal scroll direction with a large inter-item spacing (so that the items would lay out horizontally), the collection view returned an invalid intrinsic content size (-1, -1), and collectionViewContentSize returned the what was effectively the bounds of the collection view - not taking into account that there was only one row surrounded by space. In short, it was not very intrinsic. Thanks!
  • Georg
    Georg over 9 years
    didn't work for me... I am using my CollectionView inside a UITableViewCell and would like the tableview to grow in height as the collection view grows in height using iOS8 UITableViewAutomaticDimension But my collectionview stays small :(
  • rounak
    rounak over 9 years
    What's the difference between collectionViewContentSize and contentSize of the scroll view?
  • dotToString
    dotToString about 9 years
    Awesome. Short and sweet solution to my UICollectionView inside of a UIScrollView!
  • thesummersign
    thesummersign about 9 years
    @Georg, I am trying to do something similar. But when there is a deadlock. The collection view will get its layout information after cell loads on View and the cell loads after the height is calculated but the height need to be calculated from the collectionview. How did you fix this?
  • Georg
    Georg about 9 years
    One important thing is to disable scrolling and scrollbars in the collection view
  • Jun
    Jun over 8 years
    When you call contentSize of the collection view in viewDidLoad, it returns the frame of the collection view, collectionViewContentSize returns correct content size.
  • xtrinch
    xtrinch about 8 years
    Same problem as Georg, it's about 50px in height when it should be more than 400
  • Maverick1st
    Maverick1st over 7 years
    @Georg i have exactly the same problem and haven't found a solution yet. Did you find one?
  • Georg
    Georg over 7 years
    Yes, I set the collectionview to "not scrollabe, no scollbars" and then reload it then the content of the tableview is set. Also the collectionview is a subclass that returns it's content size as intrinsicContentSize. Hope that helps!
  • user1046037
    user1046037 over 7 years
    IMHO it might be better to use the collection view without using the table view. If the flow layout doesn't meet your requirement you could create your own custom layout.
  • DrMickeyLauer
    DrMickeyLauer about 7 years
    collectionViewContentSize only works on the 2nd (sometimes also 3rd) time for me, the first time it always returns a too large width (I have pinned the width, but care for a variable height), thus I have to force relayout at least once. Is there a better way?
  • Abirami Bala
    Abirami Bala about 7 years
    Im a fresher, and Im not sure about where and how to use this in my ViewController, Can you please make an edit with the answer.....?
  • Sebastian
    Sebastian about 7 years
    For me calling reloadData before querying the collectionViewContentSize size helped.
  • May Phyu
    May Phyu almost 7 years
    @MananDevani, could you please share your code or tutorial relating to this problem?. I have got such a problem right now. I don't know how to solve it. :(
  • Manan Devani
    Manan Devani almost 7 years
    @May Phyu, Create outlet connection for UICollectionViewHeight and use following method. - (void)setCollectionViewHeight { self.collectionViewHeight.constant = self.collectionView.collectionViewLayout.collectionViewConte‌​ntSize.height; } // Call this method after loading the data.
  • Mohammad Sadiq Shaikh
    Mohammad Sadiq Shaikh over 6 years
    just set this class to your collectionview in Storyboard
  • Er. Vihar
    Er. Vihar over 6 years
    @ShikhaSharma: You can add the removeObserver code within "ViewDidDisappear" method, which will remove observer only after the view confirms that its disappeared. Please check the updated answer.
  • Shikha Sharma
    Shikha Sharma over 6 years
    am getting this error : An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
  • Er. Vihar
    Er. Vihar over 6 years
    @ShikhaSharma: Sorry, It's my mistake to specify the method. Try to put removeobserver code in viewWillDisappear.
  • Chen Li Yong
    Chen Li Yong almost 6 years
    @ChrisChen TableView actually does have something similar, and even more easier. Just call myTableView.contentSize and you'll get the content size as CGSize!
  • Rahul K Rajan
    Rahul K Rajan over 5 years
    I found that its not working in iPhone 6/7 plus and XR,XS-MAX
  • Ajay Kumar
    Ajay Kumar over 5 years
    This saved me, Thanks!
  • KolaCaine
    KolaCaine over 5 years
    It's work perfectly but If you have something like UILabel above, the content from collectionView pass over other element above, do you have another solution ?
  • asanli
    asanli about 5 years
    For whom it can help: I had to do a "layoutIfNeeded()" before this so I could get it working.
  • ArielSD
    ArielSD almost 5 years
    When is collectionViewContentSize set? When can we read from it?
  • SinisterMJ
    SinisterMJ almost 3 years
    Just made use of this and it worked pretty well - it had the advantage of informing my callback before the screen actually displayed to the user, so that I was able to adjust a critical constraint size based on the final size of the UICollectionView being rendered.