61

What's happening

Currently I have an application that uses two UICollectionViews inside a UITableView. This way I create a Pulse News look like application. My problem with this is that sometimes the 6th and 11th row disappears completely, leaving a blank space where it should be the cell. I wouldn't actually mind, if all the cells were like this (and this way I could assume that I wasn't doing things correctly), but the thing is, is just happening with those specific ones.

My theory

The 6th and 11th rows are the ones that appears when I start scrolling, so by default I am able to see 5 cells, and when I do the first horizontal scrolling the 6th comes up (blank space sometimes).

What I have

The only thing I am doing at the moment is this:

 [self.collectionView registerNib:[UINib nibWithNibName:CELL_NIB_NAME bundle:nil] forCellWithReuseIdentifier:CELL_IDENTIFIER];

On the viewDidLoad. And on the creation of the cell:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    MyCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CELL_IDENTIFIER forIndexPath:indexPath];

    NSMutableDictionary *dictionary = [self.DataSource objectAtIndex:[indexPath row]];

    [cell buildViewWithDictionary:dictionary withReferenceParent:self.referenceViewController];

    return cell;
}

So on my understating nothing fancy going on here. I though there was something wrong on the data source (a dummy JSON file), but sometimes it works ok and the cell shows, so I guess from that part is ok.

So my "question": Does anyone knows what's going on? I don't really like to say that it's a bug from iOS, but I can't think of anything else.


Edit 1.0

The amazing part is that this method

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;

Is going from indexPath [0,4] to [0,6] without calculating the [0,5]. First time I actually see this happening in iOS.


Edit 2.0

I have switched the way I am creating the cells, and instead of dequeuing I am using the old way:

NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CELL_NIB_NAME owner:self options:nil];
MyCell *cell = (MyCell *)[nib objectAtIndex:0];

Still the same sad result.

Rambatino
  • 4,716
  • 1
  • 33
  • 56
Rui Peres
  • 25,741
  • 9
  • 87
  • 137
  • I get the same problem, but the cells that disappear end up being rendered below the previous cell! Very odd. I've assumed it was a bug in iOS. – Mark Ingram Feb 27 '13 at 19:45
  • Stranges things are happening. =/ But still an outstanding controller.. – Rui Peres Feb 27 '13 at 19:58
  • I have classic grid view created using collection view. I have 3 cells in a row with small gaps. Same thing happens here but seems like very randomly. From time to time one cell is placed at 4th place in a row and in it's expected place is nothing. – Tankista May 23 '13 at 15:31

12 Answers12

38

So, what did work?

1) Subclass UICollectionViewFlowLayout.

2) Set the flowLayout of my UICollectionView to my new subclass.

3) On the init method of the UICollectionViewFlowLayout subclass, set the orientation you want:

self.scrollDirection = UICollectionViewScrollDirectionHorizontal;

In my case it is Horizontal.

4) The important part:

-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
   return YES;
}

At this moment, I should theorise a bit, but honestly I don't have a clue.

Peter DeWeese
  • 18,141
  • 8
  • 79
  • 101
Rui Peres
  • 25,741
  • 9
  • 87
  • 137
  • 3
    Take a look at this bug: http://openradar.appspot.com/12433891 Could it be what you're encountering? – rob mayoff Nov 13 '12 at 21:42
  • I have to be honest Rob, strange things happen when using `UICollectionView`, not sure if it's related or not. – Rui Peres Nov 13 '12 at 21:48
  • 1
    Have you tried fiddling with cell width and height? I'm having the same rendering problem with a horizontally scrolling collection view. I get disappearing cells when my cell width is 70 and height is 70. If I keep the cell width at 70 and change the cell height to 69, it renders correctly. I can reproduce this situation every time. – Bryan Luby Nov 30 '12 at 13:19
  • 1
    @BryanLuby after doing what I did in the `shouldInvalidateLayoutForBoundsChange:`it's working perfectly. – Rui Peres Nov 30 '12 at 13:20
  • Thanks @rob-mayoff! I was having the same problem. Always random items in the first column disappearing after scrolling down and then up again. Using the one of the subclasses in http://openradar.appspot.com/12433891 fixed it for me. – Michael Luton Jan 07 '13 at 23:17
  • 1
    Unfortunately this didn't work for me, but the solution here did -> http://stackoverflow.com/questions/12927027/uicollectionview-flowlayout-not-wrapping-cells-correctly-ios If you output the rects in that function, you'll see it creates two rows / columns so you have to filter it down to 1. – Mark Ingram Feb 28 '13 at 09:25
  • This solved my crash in `layoutSubViews` that only occurs in iOS 9 (iOS 10 & 11 are fine), thanks. – xaphod Feb 05 '18 at 17:13
20

The above answers didn't work for me, but after downloading the images, I replaced the code [self.myCollectionView reloadData] with [self.myCollectionView reloadSections:[NSIndexSet indexSetWithIndex:0]]; to refresh the collectionview and it shows all cells, you can try it.

dandan78
  • 13,328
  • 13
  • 64
  • 78
Yao Li
  • 2,071
  • 1
  • 25
  • 24
8

None of the solutions given by anyone helped me in my custom layout that we need to have in our app. Instead, I had to do this: (And yeah, IT WORKS!!!)

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
    CGSize size = [self collectionViewContentSize];
    rect.size.height = size.height*2;
    NSArray *atrributes_Super = [super layoutAttributesForElementsInRect:rect];
    return atrributes_Super;
}

After all, UICollectionView is just looking for the attributes for the elements to be displayed in your screen's rect.

Saru
  • 863
  • 1
  • 15
  • 23
  • Similar thing happened here. My implementation of layoutAttributesForElementsInRect was not returning the attributes for the desired cell, that in turn was being set as .hidden = YES. – jcardenete May 09 '16 at 12:50
3

Rob's tip about the bug helped me. The bug states that if the section insets and cells widths and spacing add up exactly to the width of the screen then the first column sometimes randomly dissappears and reappears for some cells in some places. Rather than subclass or change the cell widths, I changed the section insets for left and right in my storyboard from 6 to 4 and it I haven't seen the problem again.

hoak
  • 125
  • 1
  • 7
2

As I run the same problem suddenly and spent some time figuring out one of possible reasons of cell disappearing during the scroll, I will add my answer as well.

Prerequisites of the problem:

  1. You have a UICollectionView instance
  2. You have a UICollectionViewFlowLayoutSubclass

The problem

Cells disappear from the Collection View after scrolling to the certain point.

The source of the problem is in wrong subclassing of the UICollectionViewFlowLayout.

As it explicitly said in documentation:

Every layout object should implement the following methods:

- collectionViewContentSize
- layoutAttributesForElements(in:)
- layoutAttributesForItem(at:)
- layoutAttributesForSupplementaryView(ofKind:at:) // (if your layout supports -supplementary views)
-layoutAttributesForDecorationView(ofKind:at:) // (if your layout supports decoration views)
- shouldInvalidateLayout(forBoundsChange:)

By relying on UICollectionViewFlowLayout implementation of methods above we miss the fact, that func layoutAttributesForElements(in rect: CGRect) and collectionViewContentSize will generate wrong contentSize (the size that would be correct if all the cells would have itemSize size and the content size would be corresponding. As soon as scroll offsetY will be greater that contentSize height cell will all disappear.

The solution

The solution is in proper UICollectionViewFlowLayout subclassing. Override all the methods that are required to override and everything will work just fine.

fewlinesofcode
  • 3,007
  • 1
  • 13
  • 30
1

In my case (vertical scroll, with cells disappearing in first view), cells were disappearing due to incorrect estimated size. It seems, UICollectionView uses the estimated size to calculate the items to load in first view. I'd set the estimated size too high which was resulting in wrong calculations for number of items to load in first screen.

The moment I made the estimated height bit low, all the cells appeared correctly.

shim
  • 9,289
  • 12
  • 69
  • 108
1

We ran into disappearing cells recently and found that rather than skipping 'hidden' cells we were accidentally inserting 0x0 sized cells. The resulting behavior was very confusing and did not suggest these invisible cells were the issue. We would see the correctly sized cells and layout, but a few of the valid cells would consistently disappear after scrolling off/on screen. I have no idea why intermingling 0 sized cells would cause this behavior, but removing them fixed the problem. This may not be causing your problem, but this may be helpful to devs searching for similar symptoms.

tyler
  • 2,865
  • 1
  • 23
  • 28
1

Just ran into an issue where all UICollectionView cells were disappearing on scroll.

This happened because I had declared

extension UICollectionViewLayout {
    static let defaultLayout: UICollectionViewLayout {
        let layout = UICollectionViewFlowLayout()
        layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
        return layout
    }()
}

... meaning the same layout instance was being used in multiple UICollectionViews. I had meant to make that a computed var. Hope this helps someone who's accidentally using the same layout object in multiple collection views.

Peter
  • 2,005
  • 1
  • 20
  • 14
0

What caused the cells to disappear in my case was that the data source was being deallocated prematurely. UICollectionView.dataSource is a weak property, which means that unless you keep a strong reference to it, the object will be deallocated at the end of the scope in which you created. The problem manifested itself with disappearing cells as soon as I tapped on the UICollectionView.

Francesco Puglisi
  • 2,140
  • 2
  • 18
  • 26
0

I hade to add myCollectionView.reloadData inside cellForRowAt of the cell so make sure every time creating a cell it get updated with the new data and to avoid disappearing of the cells and avoid overlapping of the content of the cells.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! DiarioTableViewCell
cell.tag = indexPath.section
cell.collectionView.reloadData() // this what fixes my cellsDisAppearing
cell.collectionView.collectionViewLayout.invalidateLayout() //just to be sure, maybe it's not necessary

return cell

}

Rui Peres
  • 25,741
  • 9
  • 87
  • 137
-1

For me this issue seemed to be related with the way i make my collectionview adapt to an open keyboard to prevent content overlaps.

in my observer to respond to KeyboardWillShow i had this:

var userInfo = obj.UserInfo[UIKeyboard.FrameEndUserInfoKey];
if (userInfo is NSValue value)
{
    var rect = value.CGRectValue;
    var windowOffset = this.Superview.ConvertPointToView(this.Frame.Location, UIApplication.SharedApplication.KeyWindow);
    var newHeight = rect.Y - windowOffset.Y;

    this._controller.CollectionView.Frame = new CGRect(0, 0, this._controller.CollectionView.Frame.Width, newHeight);
}

After changing it to this:

var userInfo = obj.UserInfo[UIKeyboard.FrameBeginUserInfoKey];
if (userInfo is NSValue value)
{
    var rect = value.CGRectValue;
    UIEdgeInsets contentInsets = new UIEdgeInsets(0, 0, rect.Height, 0);
    this._controller.CollectionView.ContentInset = contentInsets;
    this._controller.CollectionView.ScrollIndicatorInsets = contentInsets;
}

The cell disappearance issue completely went away. This is C# from working with xamarin but i hope it helps someone else.

Dbl
  • 5,634
  • 3
  • 41
  • 66
-1

I think this is not a UICollectionView‘s bug, maybe your not return right data in - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect method.

You can see this demo: https://github.com/lqcjdx/YLTagsChooser , all cells can appear when scolling the UICollectionView.