13

(EDIT : it seems to be working fine starting with iOS 9. I did not make extensive tests, but the example works. This confirms the bug present in iOS 8.)

I spent a lot of time testing UICollectionView's Flow Layout self sizing behavior. After a lot of frustration the issue is narrowed down to the fact that as soon as one sets the estimatedItemSize to a non-zero size, the scrolling no longer works properly.

In my example instead of showing 40 items it only displays 32.

I've copy pasted the code bellow. I've tested many things starting with a Swift version.

Basically it fails to calculate and/or properly update the layout's collectionViewContentSize()

Here is a complete demo http://git.io/AIrHNA

Anybody can point me in the right direction?

Thank you

@implementation ViewControllerObjcC

static NSString * const reuseIdentifier = @"Cell";
-(UICollectionViewFlowLayout*)flowLayout{
  return (UICollectionViewFlowLayout*)self.collectionViewLayout;
}

- (void)viewDidLoad {
  [super viewDidLoad];
  [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
  CGSize estimatedSize = CGSizeMake(self.view.frame.size.width, 25.0);
  BOOL testEstimatedItemSize = true;
  if (testEstimatedItemSize) {
    [self flowLayout].estimatedItemSize = estimatedSize;
  }else{
    [self flowLayout].itemSize = estimatedSize;
  }

}

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return 40;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
  UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
  UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 40, 30)];
  [cell.contentView addSubview:label];
  label.text = [NSString stringWithFormat:@"%ld",(long)indexPath.row];
  label.backgroundColor = [UIColor redColor];
  return cell;
}
Adrian
  • 1,605
  • 19
  • 21
  • 10
    I'm surprised to hear that you have been able to use `estimatedItemSize` at all. In my experience, all that happens when I use it is that I crash. My conclusion is that this feature of self-sizing cells, though advertised in the WWDC 2014 videos, never actually came online. So my advice is: don't try to use this feature, just go back to measuring item sizes "by hand" as we did in iOS 7, and you'll be fine. (Of course I'd be delighted to learn that I'm wrong about this and that it has started working...) – matt Dec 26 '14 at 19:06
  • Matt, thank you for your valuable advice. I was thinking at exactly what your are telling me while writing the initial post. Regardless, it is frustrating for me to be spending all this time researching this problem, advertised as solved at WWDC. As mentioned, I've narrowed down the problem to a simple example, and I am willing to dig to the bottom of it. I hope that I am missing something and somebody will help me see it. – Adrian Dec 26 '14 at 20:27

3 Answers3

1

From Apple's Document,

Specifically, cells that are not onscreen are assumed to be the estimated height.

This is my guess.

When the estimated height is smaller than the actual cell height, the collection view's content size prediction is smaller than the actual content size.

Therefore it display only displays 32 of the total 40 cells.

In my project, all celsl are shown when a large estimated size is used.

Dennis Li
  • 11
  • 2
0

From the documentation:

The default value of this property is CGSizeZero. Setting it to any other value causes the collection view to query each cell for its actual size using the cell’s preferredLayoutAttributesFittingAttributes: method. If all of your cells are the same height, use the itemSize property, instead of this property, to specify the cell size instead.

It seems that you don't use this preferredLayoutAttributesFittingAttributes: method in your project?, have you tried implementing it?

On the other hand, this solution looks good: Specifying one Dimension of Cells in UICollectionView using Auto Layout

Community
  • 1
  • 1
Romain
  • 267
  • 2
  • 8
0

I had the same issue. In my case, the space between items was 32. And my code was like this:

collectionViewLayout.minimumInteritemSpacing = 0
collectionViewLayout.minimumLineSpacing = 32
collectionViewLayout.scrollDirection = .horizontal
collectionViewLayout.itemSize = UICollectionViewFlowLayout.automaticSize
collectionViewLayout.estimatedItemSize = CGSize(width: 100, height: 32)

I changed minimumInteritemSpacing to 32 the same as minimumLineSpacing to fix the problem.

collectionViewLayout.minimumInteritemSpacing = 32
Miravzal
  • 1,707
  • 1
  • 10
  • 9