diff --git a/CHANGELOG.md b/CHANGELOG.md index 896a0095..5f08f890 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,9 +11,9 @@ This release closes the [2.0.0 milestone](https://github.com/Instagram/IGListKit - Diff result method `-resultWithUpdatedMovesAsDeleteInserts` removed and replaced with `-resultForBatchUpdates` [(b5aa5e3)](https://github.com/Instagram/IGListKit/commit/b5aa5e39002854c947e777c11ae241f67f24d19c) - `IGListDiffable` equality method changed from `isEqual:` to `isEqualToDiffableObject:` [(ab890fc)](https://github.com/Instagram/IGListKit/commit/ab890fc6070f170a2db5a383a6296e62dcf75678) +- Scrolling method changed from `-scrollToObject:supplementaryKinds:scrollDirection:animated` to `-scrollToObject:supplementaryKinds:scrollDirection:atScrollPosition:animated`. Added support for specifying end position. [Bofei Zhu](https://github.com/zhubofei) [(#196)](https://github.com/Instagram/IGListKit/pull/196) - Change `NSUInteger` to `NSInteger` in public API [Suraya Shivji](https://github.com/surayashivji) [(#200)](https://github.com/Instagram/IGListKit/issues/200) - ### Enhancements - Added support for supplementaryViews created from nibs. [Rawlinxx](https://github.com/rawlinxx) [(#90)](https://github.com/Instagram/IGListKit/pull/90) @@ -21,7 +21,7 @@ This release closes the [2.0.0 milestone](https://github.com/Instagram/IGListKit - Added an additional initializer for `IGListSingleSectionController` to be able to support single sections created from nibs. An example can be found [here](Examples/Examples-iOS/IGListKitExamples/ViewControllers/SingleSectionViewController.swift). - Fixed `-[IGListAdapter reloadDataWithCompletion:]` not returning early when `collectionView` or `dataSource` is nil and `completion` is nil. [Ben Asher](https://github.com/benasher44) [(#51)](https://github.com/Instagram/IGListKit/pull/51) - Added `-isFirstSection` and `-isLastSection` APIs to `IGListSectionController` -- Added support for cells created from storyboard. [Bofei Zhu](https://github.com/zhubofei) [(#92)](https://github.com/Instagram/IGListKit/pull/92) +- Added support for cells and supplementaryViews created from storyboard. [Bofei Zhu](https://github.com/zhubofei) [(#92)](https://github.com/Instagram/IGListKit/pull/92) - Added examples for Today & iMessage extensions. [Sherlouk](https://github.com/Sherlouk) [(#112)](https://github.com/Instagram/IGListKit/pull/112) - Added `tvOS` support. [Jesse Squires](https://github.com/jessesquires) [(#137)](https://github.com/Instagram/IGListKit/pull/137) - Added `tvOS` example pack. [Sherlouk](https://github.com/Sherlouk) [(#141)](https://github.com/Instagram/IGListKit/pull/141) diff --git a/Source/IGListAdapter.h b/Source/IGListAdapter.h index 9676cc2d..914849b4 100644 --- a/Source/IGListAdapter.h +++ b/Source/IGListAdapter.h @@ -195,11 +195,13 @@ IGLK_SUBCLASSING_RESTRICTED @param object The object to which to scroll. @param supplementaryKinds The types of supplementary views in the section. @param scrollDirection A flag indicating the direction to scroll. + @param scrollPosition An option that specifies where the item should be positioned when scrolling finishes. @param animated A flag indicating if the transition should be animated. */ - (void)scrollToObject:(id)object supplementaryKinds:(nullable NSArray *)supplementaryKinds scrollDirection:(UICollectionViewScrollDirection)scrollDirection + scrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated; /** diff --git a/Source/IGListAdapter.m b/Source/IGListAdapter.m index 574739a1..0cdf3c56 100644 --- a/Source/IGListAdapter.m +++ b/Source/IGListAdapter.m @@ -141,6 +141,7 @@ - (void)scrollToObject:(id)object supplementaryKinds:(NSArray *)supplementaryKinds scrollDirection:(UICollectionViewScrollDirection)scrollDirection + scrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated { IGAssertMainThread(); IGParameterAssert(object != nil); @@ -166,33 +167,72 @@ NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:section]; NSArray *attributes = [self layoutAttributesForIndexPath:indexPath supplementaryKinds:supplementaryKinds]; - CGFloat offset = 0.0; + CGFloat offsetMin = 0.0; + CGFloat offsetMax = 0.0; for (UICollectionViewLayoutAttributes *attribute in attributes) { const CGRect frame = attribute.frame; - CGFloat origin; + CGFloat originMin; + CGFloat endMax; switch (scrollDirection) { case UICollectionViewScrollDirectionHorizontal: - origin = CGRectGetMinX(frame); + originMin = CGRectGetMinX(frame); + endMax = CGRectGetMaxX(frame); break; case UICollectionViewScrollDirectionVertical: - origin = CGRectGetMinY(frame); + originMin = CGRectGetMinY(frame); + endMax = CGRectGetMaxY(frame); break; } // find the minimum origin value of all the layout attributes - if (attribute == attributes.firstObject || origin < offset) { - offset = origin; + if (attribute == attributes.firstObject || originMin < offsetMin) { + offsetMin = originMin; + } + // find the maximum end value of all the layout attributes + if (attribute == attributes.firstObject || endMax > offsetMax) { + offsetMax = endMax; } } - + + const CGFloat offsetMid = (offsetMin + offsetMax) / 2.0; + const CGFloat collectionViewWidth = collectionView.bounds.size.width; + const CGFloat collectionViewHeight = collectionView.bounds.size.height; const UIEdgeInsets contentInset = collectionView.contentInset; CGPoint contentOffset = collectionView.contentOffset; switch (scrollDirection) { case UICollectionViewScrollDirectionHorizontal: - contentOffset.x = offset - contentInset.left; + switch (scrollPosition) { + case UICollectionViewScrollPositionRight: + contentOffset.x = offsetMax - collectionViewWidth - contentInset.left; + break; + case UICollectionViewScrollPositionCenteredHorizontally: + contentOffset.x = offsetMid - collectionViewWidth / 2.0 - contentInset.left; + break; + case UICollectionViewScrollPositionLeft: + case UICollectionViewScrollPositionNone: + case UICollectionViewScrollPositionTop: + case UICollectionViewScrollPositionBottom: + case UICollectionViewScrollPositionCenteredVertically: + contentOffset.x = offsetMin - contentInset.left; + break; + } break; case UICollectionViewScrollDirectionVertical: - contentOffset.y = offset - contentInset.top; + switch (scrollPosition) { + case UICollectionViewScrollPositionBottom: + contentOffset.y = offsetMax - collectionViewHeight - contentInset.top; + break; + case UICollectionViewScrollPositionCenteredVertically: + contentOffset.y = offsetMid - collectionViewHeight / 2.0 - contentInset.top; + break; + case UICollectionViewScrollPositionTop: + case UICollectionViewScrollPositionNone: + case UICollectionViewScrollPositionLeft: + case UICollectionViewScrollPositionRight: + case UICollectionViewScrollPositionCenteredHorizontally: + contentOffset.y = offsetMin - contentInset.top; + break; + } break; } diff --git a/Tests/IGListAdapterTests.m b/Tests/IGListAdapterTests.m index 1253a478..461881c2 100644 --- a/Tests/IGListAdapterTests.m +++ b/Tests/IGListAdapterTests.m @@ -546,14 +546,18 @@ XCTAssertEqual(CGPointEqualToPoint(point, p), YES); \ self.dataSource.objects = @[@1, @2, @3, @4, @5, @6]; [self.adapter reloadDataWithCompletion:nil]; XCTAssertEqual([self.collectionView numberOfSections], 6); - [self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical animated:NO]; + [self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 0, 0); - [self.adapter scrollToObject:@2 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical animated:NO]; + [self.adapter scrollToObject:@2 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 0, 10); - [self.adapter scrollToObject:@3 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical animated:NO]; + [self.adapter scrollToObject:@3 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 0, 30); - [self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical animated:NO]; + [self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 0, 150); + [self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO]; + IGAssertEqualPoint([self.collectionView contentOffset], 0, 105); + [self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionBottom animated:NO]; + IGAssertEqualPoint([self.collectionView contentOffset], 0, 60); } - (void)test_whenScrollHorizontallyToItem { @@ -562,13 +566,17 @@ XCTAssertEqual(CGPointEqualToPoint(point, p), YES); \ self.layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; [self.adapter reloadDataWithCompletion:nil]; XCTAssertEqual([self.collectionView numberOfSections], 6); - [self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal animated:NO]; + [self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionNone animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 0, 0); - [self.adapter scrollToObject:@2 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal animated:NO]; + [self.adapter scrollToObject:@2 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionNone animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 100, 0); - [self.adapter scrollToObject:@3 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal animated:NO]; + [self.adapter scrollToObject:@3 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionNone animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 200, 0); - [self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal animated:NO]; + [self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionNone animated:NO]; + IGAssertEqualPoint([self.collectionView contentOffset], 500, 0); + [self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO]; + IGAssertEqualPoint([self.collectionView contentOffset], 500, 0); + [self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionRight animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 500, 0); self.layout.scrollDirection = UICollectionViewScrollDirectionVertical; } @@ -588,9 +596,9 @@ XCTAssertEqual(CGPointEqualToPoint(point, p), YES); \ [self.adapter performUpdatesAnimated:NO completion:nil]; XCTAssertNotNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]); - [self.adapter scrollToObject:@1 supplementaryKinds:@[UICollectionElementKindSectionHeader] scrollDirection:UICollectionViewScrollDirectionVertical animated:NO]; + [self.adapter scrollToObject:@1 supplementaryKinds:@[UICollectionElementKindSectionHeader] scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 0, 0); - [self.adapter scrollToObject:@2 supplementaryKinds:@[UICollectionElementKindSectionHeader] scrollDirection:UICollectionViewScrollDirectionVertical animated:NO]; + [self.adapter scrollToObject:@2 supplementaryKinds:@[UICollectionElementKindSectionHeader] scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 0, 20); } @@ -610,9 +618,9 @@ XCTAssertEqual(CGPointEqualToPoint(point, p), YES); \ XCTAssertNotNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]); XCTAssertNotNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]); - [self.adapter scrollToObject:@1 supplementaryKinds:@[UICollectionElementKindSectionHeader, UICollectionElementKindSectionFooter] scrollDirection:UICollectionViewScrollDirectionVertical animated:NO]; + [self.adapter scrollToObject:@1 supplementaryKinds:@[UICollectionElementKindSectionHeader, UICollectionElementKindSectionFooter] scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 0, 0); - [self.adapter scrollToObject:@2 supplementaryKinds:@[UICollectionElementKindSectionHeader, UICollectionElementKindSectionFooter] scrollDirection:UICollectionViewScrollDirectionVertical animated:NO]; + [self.adapter scrollToObject:@2 supplementaryKinds:@[UICollectionElementKindSectionHeader, UICollectionElementKindSectionFooter] scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 0, 30); } @@ -620,7 +628,7 @@ XCTAssertEqual(CGPointEqualToPoint(point, p), YES); \ self.dataSource.objects = @[]; [self.adapter reloadDataWithCompletion:nil]; XCTAssertEqual([self.collectionView numberOfSections], 0); - [self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical animated:NO]; + [self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 0, 0); } @@ -629,13 +637,13 @@ XCTAssertEqual(CGPointEqualToPoint(point, p), YES); \ self.dataSource.objects = @[@1, @2, @3, @4]; [self.adapter reloadDataWithCompletion:nil]; XCTAssertEqual([self.collectionView numberOfSections], 4); - [self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical animated:NO]; + [self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 0, 0); - [self.adapter scrollToObject:@5 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical animated:NO]; + [self.adapter scrollToObject:@5 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 0, 0); - [self.adapter scrollToObject:@2 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical animated:NO]; + [self.adapter scrollToObject:@2 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 0, 10); - [self.adapter scrollToObject:@5 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical animated:NO]; + [self.adapter scrollToObject:@5 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO]; IGAssertEqualPoint([self.collectionView contentOffset], 0, 10); }