Invalidate layout when using reloadData

Summary:
Always invalidate the `collectionViewLayout` when calling `reloadData`. Turns out there are inconsistencies when layout attributes are queries/stored using `UICollectionViewFlowLayout` and `estimatedItemSize`.

Reproduced in unit test, fixed the test.

Closes #305

- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
Closes https://github.com/Instagram/IGListKit/pull/319

Differential Revision: D4329318

Pulled By: rnystrom

fbshipit-source-id: 91851f6ab170a416810712308727225404ad59ba
This commit is contained in:
Ryan Nystrom 2016-12-15 10:50:34 -08:00 committed by Facebook Github Bot
parent 9600c23d15
commit 1765d68406
2 changed files with 42 additions and 0 deletions

View file

@ -84,6 +84,7 @@
[delegate listAdapterUpdater:self willReloadDataWithCollectionView:collectionView];
[collectionView reloadData];
[collectionView.collectionViewLayout invalidateLayout];
[collectionView layoutIfNeeded];
[delegate listAdapterUpdater:self didReloadDataWithCollectionView:collectionView];

View file

@ -418,4 +418,45 @@
[mockDelegate verify];
}
- (void)test_whenCallingReloadData_withUICollectionViewFlowLayout_withEstimatedSize_thatSectionItemCountsCorrect {
UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new];
// setting the estimated size of a layout causes UICollectionView to requery layout attributes during reloadData
// this becomes out of sync with the data source if the section/item count changes
layout.estimatedItemSize = CGSizeMake(100, 10);
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) collectionViewLayout:layout];
IGListTestUICollectionViewDataSource *dataSource = [[IGListTestUICollectionViewDataSource alloc] initWithCollectionView:collectionView];
// 2 sections, 1 item in 1st, 4 items in 2nd
dataSource.sections = @[
[IGSectionObject sectionWithObjects:@[@1]],
[IGSectionObject sectionWithObjects:@[@1, @2, @3, @4]]
];
// assert the initial state of the collection view WITHOUT any layoutSubviews or anything
XCTAssertEqual([collectionView numberOfSections], 2);
XCTAssertEqual([collectionView numberOfItemsInSection:0], 1);
XCTAssertEqual([collectionView numberOfItemsInSection:1], 4);
dataSource.sections = @[
[IGSectionObject sectionWithObjects:@[@1]],
];
IGListAdapterUpdater *updater = [IGListAdapterUpdater new];
[updater performReloadDataWithCollectionView:collectionView];
XCTAssertEqual([collectionView numberOfSections], 1);
XCTAssertEqual([collectionView numberOfItemsInSection:0], 1);
dataSource.sections = @[
[IGSectionObject sectionWithObjects:@[@1]],
[IGSectionObject sectionWithObjects:@[@1, @2, @3, @4]]
];
[updater performReloadDataWithCollectionView:collectionView];
XCTAssertEqual([collectionView numberOfSections], 2);
XCTAssertEqual([collectionView numberOfItemsInSection:0], 1);
XCTAssertEqual([collectionView numberOfItemsInSection:1], 4);
}
@end