UICollectionView automatically increases height

How to resize a UICollectionView so that it fully displays its contents? I tried many things, including setting up its frame, calling reloadData and layout invalidation:

 self.collectionView.contentSize = CGSizeMake(300, 2000); self.collectionView.frame = CGRectMake(0, 0, 300, 2000); [self.collectionView reloadData]; [self.collectionView.collectionViewLayout invalidateLayout]; 

but none of this has any effect. After clicking the button, I still see the initial view, for example:

collection view only showing part of the content after frame resize

I have a small demo program where I have a data source producing 100 elements. In Interface Builder, I initially set the size of the UICollectionView to a small value so that not all elements match, after which I press the button, after which the code above is executed. I expect the UICollectionView to now show all the elements, but that is not the case.

EDIT: Demo program can be found at https://github.com/mjdemilliano/TestUICollectionView .

EDIT2: I noticed that the frame update is lost at some point, because if I press the button again, the current frame will revert to the old value. After adding some log statements to the button event handler, log output:

 before: frame = {{0, 58}, {320, 331}}, contentSize = {320, 1190} update button pressed after: frame = {{0, 0}, {300, 2000}}, contentSize = {300, 2000} before: frame = {{0, 58}, {320, 331}}, contentSize = {320, 1190} update button pressed after: frame = {{0, 0}, {300, 2000}}, contentSize = {300, 2000} 

I don’t understand why the frame change is not saved, what changes it.

At some point, I will replace the hard-coded values ​​with the values ​​obtained from the stream layout, but I would like to exclude this and keep my example as simple as possible.

Context: what I want to end up doing is this: I have a scrollable view with various controls, such as labels and images, and a collection view with dynamic content. I want to scroll through all of this, not just view the collection, so I don't use my own scroll viewers that work great.

+47
ios objective-c nslayoutconstraint uicollectionview
Dec 26 '13 at 10:50
source share
7 answers

I decided this in the end, fixing all the Auto Layout errors, setting the height of the collection view using a constraint. Then, when I know the content has changed, I update the restriction value using the value of collectionView.contentSize.height :

 self.verticalLayoutConstraint.constant = self.collectionView.contentSize.height; 

Then the collection view changes correctly, and it behaves well in the overall scrolling. I updated the GitHub test project with the changes.

For me, having done this by updating the constraint manually, instead of telling iOS: “make the frame height in the collection view as large as necessary” does not seem right to me, but this is the best I've come up with so far. Please write the best answer if you have one.

+102
Dec 29 '13 at 20:27
source share

Here is my implementation in Swift 3:

 override func sizeThatFits(_ size: CGSize) -> CGSize { if (self.superview != nil) { self.superview?.layoutIfNeeded() } return collectionView.contentSize } 
+3
May 7 '17 at 20:35
source share
 UICollectionViewFlowLayout *flowLayout; flowLayout = [[UICollectionViewFlowLayout alloc]init]; [flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical]; [flowLayout setMinimumInteritemSpacing:0.0f]; [flowLayout setMinimumLineSpacing:0.0f]; [self.collectionView setPagingEnabled:NO]; [flowLayout setItemSize:CGSizeMake(322.0, 148.0)]; //important to leave no white space between the images [self.collectionView setCollectionViewLayout:flowLayout]; 

I found that autorun in a storyboard does not help much. The right setup for the UICollectionViewFlowLayout for your View collection is real help. If you resize an element using setItemSize, you can get the desired result.

+2
Feb 03 '15 at 16:15
source share

Here you can associate the height of the CollectionView with its internal size. I used it for the correct size of the CollectionView inside the CellView TableView (with dynamic cell height). and it works great.

First add this to a subclass of UICollectionView:

 override var intrinsicContentSize: CGSize { get { return self.contentSize } } 

Then call layoutIfNeeded () after reloading the data:

 reloadData() layoutIfNeeded() 
+2
Sep 11 '17 at 19:32
source share

The easiest method I found is to override sizeThatFits: methods as is:

 - (CGSize)sizeThatFits:(CGSize)size { if( self.superview ) [self.superview layoutIfNeeded]; // to force evaluate the real layout return self.collectionViewLayout.collectionViewContentSize; } 
+1
Jan 26 '17 at 15:18
source share

You can try my custom class AGCollectionView

  • Assign the collectionView height limit using a storyboard or programmatically.

- Assign this class to your UICollectionView .

 class AGCollectionView: UICollectionView { fileprivate var heightConstraint: NSLayoutConstraint! override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) { super.init(frame: frame, collectionViewLayout: layout) self.associateConstraints() } required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self.associateConstraints() } override open func layoutSubviews() { super.layoutSubviews() if self.heightConstraint != nil { self.heightConstraint.constant = floor(self.contentSize.height) } else{ self.sizeToFit() print("Set a heightConstraint set size to fit content") } } func associateConstraints() { // iterate through height constraints and identify for constraint: NSLayoutConstraint in constraints { if constraint.firstAttribute == .height { if constraint.relation == .equal { heightConstraint = constraint } } } } } 
0
Mar 31 '18 at 5:40
source share

It’s even easier for me, I think

 -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { //add following code line after adding cells, before Return ........... ......... scrollView.contentSize = = collectionView.contentSize; //now scrollView size is equal to collectionView size. No matter how small or big it is. return cell; } 
-3
Oct 29 '14 at 21:05
source share



All Articles