Restore scrollToObject: API with layout fix

Summary:
Reverting the revert in D5651413. The origin PR:

https://github.com/Instagram/IGListKit/pull/808/files

Had a small bug in it that wasn't captured via unit tests b/c we use a custom layout. However this should also repro in `IGListCollectionViewLayout`, but none of our tests combine the two atm.

Differential Revision: D5651585

fbshipit-source-id: da6c67cba57ab1aad51535467bff86a21f16f2fa
This commit is contained in:
Ryan Nystrom 2017-08-21 07:05:43 -07:00 committed by Facebook Github Bot
parent 7b56f64794
commit ae3604c3fe
3 changed files with 57 additions and 7 deletions

View file

@ -14,6 +14,7 @@ The changelog for `IGListKit`. Also see the [releases](https://github.com/instag
- Prevent a crash when update queued immediately after item batch update. [Ryan Nystrom](https://github.com/rnystrom) (tbd)
- Return correct `-[IGListAdapter visibleSectionControllers]` when section has no items, but has supplementary views. [Mani Ghasemlou](https://github.com/manicakes) [(#643)](https://github.com/Instagram/IGListKit/issues/643)
- Call `[CATransaction commit]` before calling completion block in IGListAdapterUpdater to prevent animation issues. [Maxime Ollivier](https://github.com/maxoll) (tbd)
- Fix `scrollToObject:supplementaryKinds:...` not scrolling when section is empty but does have supplymentary views
### Enhancements

View file

@ -172,20 +172,33 @@
}
UICollectionView *collectionView = self.collectionView;
const NSInteger numberOfItems = [collectionView numberOfItemsInSection:section];
if (numberOfItems == 0) {
return;
}
UICollectionViewLayout *layout = self.collectionView.collectionViewLayout;
// force layout before continuing
// this method is typcially called before pushing a view controller
// thus, before the layout process has actually happened
[collectionView setNeedsLayout];
[collectionView layoutIfNeeded];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:section];
// collect the layout attributes for the cell and supplementary views for the first index
// this will break if there are supplementary views beyond item 0
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:section];
NSArray *attributes = [self layoutAttributesForIndexPath:indexPath supplementaryKinds:supplementaryKinds];
NSArray *attributes = nil;
const NSInteger numberOfItems = [collectionView numberOfItemsInSection:section];
if (numberOfItems > 0) {
attributes = [self layoutAttributesForIndexPath:indexPath supplementaryKinds:supplementaryKinds];
} else {
NSMutableArray *supplementaryAttributes = [NSMutableArray new];
for (NSString* supplementaryKind in supplementaryKinds) {
UICollectionViewLayoutAttributes *supplementaryAttribute = [layout layoutAttributesForSupplementaryViewOfKind:supplementaryKind atIndexPath:indexPath];
if (supplementaryAttribute != nil) {
[supplementaryAttributes addObject: supplementaryAttribute];
}
}
attributes = supplementaryAttributes;
}
CGFloat offsetMin = 0.0;
CGFloat offsetMax = 0.0;
@ -273,7 +286,6 @@
[collectionView setContentOffset:contentOffset animated:animated];
}
#pragma mark - Editing
- (void)performUpdatesAnimated:(BOOL)animated completion:(IGListUpdaterCompletion)completion {

View file

@ -652,6 +652,43 @@
IGAssertEqualPoint([self.collectionView contentOffset], 0, 60);
}
- (void)test_whenScrollVerticallyToItemInASectionWithNoCellsAndNoSupplymentaryView {
self.dataSource.objects = @[@1, @0, @300];
[self.adapter reloadDataWithCompletion:nil];
XCTAssertEqual([self.collectionView numberOfSections], 3);
[self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
[self.adapter scrollToObject:@0 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
[self.adapter scrollToObject:@300 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
IGAssertEqualPoint([self.collectionView contentOffset], 0, 10);
}
- (void)test_whenScrollVerticallyToItemInASectionWithNoCellsButAHeaderSupplymentaryView {
self.dataSource.objects = @[@1, @0, @300];
[self.adapter reloadDataWithCompletion:nil];
IGTestSupplementarySource *supplementarySource = [IGTestSupplementarySource new];
supplementarySource.collectionContext = self.adapter;
supplementarySource.supportedElementKinds = @[UICollectionElementKindSectionHeader];
IGListSectionController *controller = [self.adapter sectionControllerForObject:@0];
controller.supplementaryViewSource = supplementarySource;
supplementarySource.sectionController = controller;
[self.adapter performUpdatesAnimated:NO completion:nil];
XCTAssertEqual([self.collectionView numberOfSections], 3);
[self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
[self.adapter scrollToObject:@0 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
[self.adapter scrollToObject:@0 supplementaryKinds:@[UICollectionElementKindSectionHeader] scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionTop animated:NO];
IGAssertEqualPoint([self.collectionView contentOffset], 0, 10);
[self.adapter scrollToObject:@300 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
IGAssertEqualPoint([self.collectionView contentOffset], 0, 20);
}
- (void)test_whenScrollHorizontallyToItem {
// # of items for each object == [item integerValue], so @2 has 2 items (cells)
IGListTestAdapterHorizontalDataSource *dataSource = [[IGListTestAdapterHorizontalDataSource alloc] init];