From 623ff2a8a85e0e2e8d0331ae3250d67985cd06b6 Mon Sep 17 00:00:00 2001 From: Ryan Nystrom Date: Thu, 30 Mar 2017 09:23:32 -0700 Subject: [PATCH] Container size doesnt use content inset, add new APIs Summary: The content inset of a collection view can change at any time (as it does with our refresh control) and isn't a good measure of the container size. I don't want to totally remove that API though, so I changed the default behavior, added an insets API, and also added the functionality of the original in a new API. This makes sizes much more deterministic. Reviewed By: jessesquires Differential Revision: D4800758 fbshipit-source-id: 85ce843b5b1c297cea2e2ea705fa255617cbe356 --- CHANGELOG.md | 2 ++ .../ImageSectionController.m | 22 ++++++++++++++++ Source/IGListAdapter.m | 11 +++++++- Source/IGListCollectionContext.h | 12 ++++++++- Source/IGListStackedSectionController.m | 8 ++++++ Tests/IGListAdapterTests.m | 22 ++++++++++++++++ Tests/IGListStackSectionControllerTests.m | 26 +++++++++++++++++++ 7 files changed, 101 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d35b4240..f288fd36d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,8 @@ This release closes the [3.0.0 milestone](https://github.com/Instagram/IGListKit } completion:nil]; ``` +- `-[IGListCollectionContext containerSize]` no longer accounts for the content inset of the collection view when returning a size. If you require that behavior, you can now use `-[IGListCollectionContext insetContainerSize]`. [Ryan Nystrom](https://github.com/rnystrom) (tbd) + ### Enhancements diff --git a/Examples/Examples-iOS/IGListKitExamples/SectionControllers/ImageSectionController.m b/Examples/Examples-iOS/IGListKitExamples/SectionControllers/ImageSectionController.m index 601b16774..b7fac57f7 100644 --- a/Examples/Examples-iOS/IGListKitExamples/SectionControllers/ImageSectionController.m +++ b/Examples/Examples-iOS/IGListKitExamples/SectionControllers/ImageSectionController.m @@ -15,6 +15,10 @@ #import "ImageSectionController.h" #import "PhotoCell.h" +@interface ImageSectionController () + +@end + @implementation ImageSectionController #pragma mark - IGListSectionType @@ -39,4 +43,22 @@ - (void)didSelectItemAtIndex:(NSInteger)index { } +- (id)supplementaryViewSource { + return self; +} + +- (NSArray *)supportedElementKinds { + return @[UICollectionElementKindSectionFooter]; +} + +- (CGSize)sizeForSupplementaryViewOfKind:(NSString *)elementKind atIndex:(NSInteger)index { + return CGSizeMake(self.collectionContext.containerSize.width, 30); +} + +- (UICollectionReusableView *)viewForSupplementaryElementOfKind:(NSString *)elementKind atIndex:(NSInteger)index { + UICollectionReusableView *view = [self.collectionContext dequeueReusableSupplementaryViewOfKind:elementKind forSectionController:self class:[UICollectionReusableView class] atIndex:index]; + view.backgroundColor = [UIColor yellowColor]; + return view; +} + @end diff --git a/Source/IGListAdapter.m b/Source/IGListAdapter.m index 4f3e84cff..a2a50f715 100644 --- a/Source/IGListAdapter.m +++ b/Source/IGListAdapter.m @@ -817,7 +817,16 @@ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL #pragma mark - IGListCollectionContext - (CGSize)containerSize { - return UIEdgeInsetsInsetRect(self.collectionView.bounds, self.collectionView.contentInset).size; + return self.collectionView.bounds.size; +} + +- (UIEdgeInsets)containerInset { + return self.collectionView.contentInset; +} + +- (CGSize)insetContainerSize { + IGListCollectionView *collectionView = self.collectionView; + return UIEdgeInsetsInsetRect(collectionView.bounds, collectionView.contentInset).size; } - (CGSize)containerSizeForSectionController:(IGListSectionController *)sectionController { diff --git a/Source/IGListCollectionContext.h b/Source/IGListCollectionContext.h index a0236fc2d..32c3ce0f7 100644 --- a/Source/IGListCollectionContext.h +++ b/Source/IGListCollectionContext.h @@ -24,10 +24,20 @@ NS_ASSUME_NONNULL_BEGIN @protocol IGListCollectionContext /** - The size of the collection view. You may use this for sizing cells. + The size of the collection view. You can use this for sizing cells. */ @property (nonatomic, readonly) CGSize containerSize; +/** + The content insets of the collection view. You can use this for sizing cells. + */ +@property (nonatomic, readonly) UIEdgeInsets containerInset; + +/** + The size of the collection view with content insets applied. + */ +@property (nonatomic, readonly) CGSize insetContainerSize; + /** Returns size of the collection view relative to the section controller. diff --git a/Source/IGListStackedSectionController.m b/Source/IGListStackedSectionController.m index 28273ce76..9ea8439f3 100644 --- a/Source/IGListStackedSectionController.m +++ b/Source/IGListStackedSectionController.m @@ -165,6 +165,14 @@ - (CGSize)containerSize { return [self.collectionContext containerSize]; } +- (UIEdgeInsets)containerInset { + return [self.collectionContext containerInset]; +} + +- (CGSize)insetContainerSize { + return [self.collectionContext insetContainerSize]; +} + - (CGSize)containerSizeForSectionController:(IGListSectionController *)sectionController { const UIEdgeInsets inset = sectionController.inset; return CGSizeMake(self.containerSize.width - inset.left - inset.right, diff --git a/Tests/IGListAdapterTests.m b/Tests/IGListAdapterTests.m index 1b2704558..2f2f994cb 100644 --- a/Tests/IGListAdapterTests.m +++ b/Tests/IGListAdapterTests.m @@ -1111,4 +1111,26 @@ - (void)test_whenSupplementarySourceReturnsNegativeSize_thatAdapterReturnsZero { XCTAssertEqual(size.height, 0.0); } +- (void)test_whenQueryingContainerInset_thatMatchesCollectionView { + self.dataSource.objects = @[@2]; + [self.adapter reloadDataWithCompletion:nil]; + self.collectionView.contentInset = UIEdgeInsetsMake(1, 2, 3, 4); + IGListSectionController *controller = [self.adapter sectionControllerForObject:@2]; + const UIEdgeInsets inset = [controller.collectionContext containerInset]; + XCTAssertEqual(inset.top, 1); + XCTAssertEqual(inset.left, 2); + XCTAssertEqual(inset.bottom, 3); + XCTAssertEqual(inset.right, 4); +} + +- (void)test_whenQueryingInsetContainerSize_thatResultIsBoundsInsetByContent { + self.dataSource.objects = @[@2]; + [self.adapter reloadDataWithCompletion:nil]; + self.collectionView.contentInset = UIEdgeInsetsMake(1, 2, 3, 4); + IGListSectionController *controller = [self.adapter sectionControllerForObject:@2]; + const CGSize size = [controller.collectionContext insetContainerSize]; + XCTAssertEqual(size.width, 94); + XCTAssertEqual(size.height, 96); +} + @end diff --git a/Tests/IGListStackSectionControllerTests.m b/Tests/IGListStackSectionControllerTests.m index 8ede79109..cdbf8f715 100644 --- a/Tests/IGListStackSectionControllerTests.m +++ b/Tests/IGListStackSectionControllerTests.m @@ -158,6 +158,32 @@ - (void)test_whenSectionEdgeInsetIsNotZero { IGAssertEqualSize([stack containerSizeForSectionController:section1], 98, 98); } +- (void)test_whenQueryingContainerInset_thatMatchesCollectionView { + self.collectionView.contentInset = UIEdgeInsetsMake(1, 2, 3, 4); + [self setupWithObjects:@[ + [[IGTestObject alloc] initWithKey:@0 value:@[@42]] + ]]; + IGListStackedSectionController *stack = [self.adapter sectionControllerForObject:self.dataSource.objects[0]]; + IGListTestContainerSizeSection *section1 = stack.sectionControllers[0]; + const UIEdgeInsets inset = [section1.collectionContext containerInset]; + XCTAssertEqual(inset.top, 1); + XCTAssertEqual(inset.left, 2); + XCTAssertEqual(inset.bottom, 3); + XCTAssertEqual(inset.right, 4); +} + +- (void)test_whenQueryingInsetContainerSize_thatBoundsInsetByContent { + self.collectionView.contentInset = UIEdgeInsetsMake(1, 2, 3, 4); + [self setupWithObjects:@[ + [[IGTestObject alloc] initWithKey:@0 value:@[@42]] + ]]; + IGListStackedSectionController *stack = [self.adapter sectionControllerForObject:self.dataSource.objects[0]]; + IGListTestContainerSizeSection *section1 = stack.sectionControllers[0]; + const CGSize size = [section1.collectionContext insetContainerSize]; + XCTAssertEqual(size.width, 94); + XCTAssertEqual(size.height, 96); +} + - (void)test_whenQueryingCellIndex_thatIndexIsRelativeToSectionController { [self setupWithObjects:@[ [[IGTestObject alloc] initWithKey:@0 value:@[@1, @1, @2]]