mirror of
https://github.com/Instagram/IGListKit
synced 2026-05-23 17:28:22 +00:00
Get index path or scroll position of first visible item in list (#1544)
Summary: Pull Request resolved: https://github.com/Instagram/IGListKit/pull/1544 Refactored and added functions to IGListAdapter for getting index path or scroll position of first visible item in list. This makes it possible to see which item is the current first visible item scrolled to in the list, and determine how far it is scrolled into (analogous to additionalOffset in scrollToObject:). Reviewed By: lorixx Differential Revision: D32196398 fbshipit-source-id: d809d5f96bb4e1d95055dbebe4e55c1a428a40ed
This commit is contained in:
parent
05dd3cb71e
commit
987055532a
3 changed files with 367 additions and 73 deletions
|
|
@ -256,7 +256,7 @@ NS_SWIFT_NAME(ListAdapter)
|
|||
@param scrollPosition An option that specifies where the item should be positioned when scrolling finishes.
|
||||
@param additionalOffset Additional offset amount from the scroll position.
|
||||
@param animated A flag indicating if the scrolling should be animated.
|
||||
|
||||
|
||||
@note The additional offset amount is to shift the final scroll position by some horizontal or vertical amount
|
||||
depending on the scroll direction. This is necessary when scrolling to an object on a view with sticky headers, since
|
||||
the sticky header would otherwise cover the top portion of the object.
|
||||
|
|
@ -268,6 +268,27 @@ NS_SWIFT_NAME(ListAdapter)
|
|||
additionalOffset:(CGFloat)additionalOffset
|
||||
animated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
Returns the index path for the first visible cell that has been scrolled to.
|
||||
This refers to the cell currently at the top/left (0, 0) of the collection view's frame,
|
||||
inset by the collection view's contentInset top or left value if defined.
|
||||
|
||||
@return The index path of the cell or nil if not found.
|
||||
*/
|
||||
- (nullable NSIndexPath *)indexPathForFirstVisibleItem;
|
||||
|
||||
/**
|
||||
Gets the scroll offset of the first visible cell scrolled into in the collection view.
|
||||
This refers to the cell currently at the top/left (0, 0) of the collection view's frame,
|
||||
inset by the collection view's contentInset top or left value if defined.
|
||||
|
||||
@param scrollDirection An option indicating the direction to scroll.
|
||||
|
||||
@return additionalOffset is the offset amount the first visible cell is shifted from the start of the cell,
|
||||
the amount it has been scrolled into in the coordinates of the cell's bounds.
|
||||
*/
|
||||
- (CGFloat)offsetForFirstVisibleItemWithScrollDirection:(UICollectionViewScrollDirection)scrollDirection;
|
||||
|
||||
/**
|
||||
Returns the size of a cell at the specified index path.
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@
|
|||
#import "UICollectionViewLayout+InteractiveReordering.h"
|
||||
#import "UIScrollView+IGListKit.h"
|
||||
|
||||
typedef struct OffsetRange {
|
||||
CGFloat min;
|
||||
CGFloat max;
|
||||
} OffsetRange;
|
||||
|
||||
@implementation IGListAdapter {
|
||||
NSMapTable<UICollectionReusableView *, IGListSectionController *> *_viewSectionControllerMap;
|
||||
// An array of blocks to execute once batch updates are finished
|
||||
|
|
@ -200,7 +205,7 @@
|
|||
#pragma mark - Scrolling
|
||||
|
||||
- (void)scrollToObject:(id)object
|
||||
supplementaryKinds:(NSArray<NSString *> *)supplementaryKinds
|
||||
supplementaryKinds:(nullable NSArray<NSString *> *)supplementaryKinds
|
||||
scrollDirection:(UICollectionViewScrollDirection)scrollDirection
|
||||
scrollPosition:(UICollectionViewScrollPosition)scrollPosition
|
||||
additionalOffset:(CGFloat)additionalOffset
|
||||
|
|
@ -221,13 +226,108 @@
|
|||
|
||||
NSIndexPath *indexPathFirstElement = [NSIndexPath indexPathForItem:0 inSection:section];
|
||||
|
||||
const OffsetRange offset = [self _offsetRangeForIndexPath:indexPathFirstElement
|
||||
supplementaryKinds:supplementaryKinds
|
||||
scrollDirection:scrollDirection];
|
||||
|
||||
const CGFloat offsetMid = (offset.min + offset.max) / 2.0;
|
||||
const CGFloat collectionViewWidth = collectionView.bounds.size.width;
|
||||
const CGFloat collectionViewHeight = collectionView.bounds.size.height;
|
||||
const UIEdgeInsets contentInset = collectionView.ig_contentInset;
|
||||
CGPoint contentOffset = collectionView.contentOffset;
|
||||
switch (scrollDirection) {
|
||||
case UICollectionViewScrollDirectionHorizontal: {
|
||||
switch (scrollPosition) {
|
||||
case UICollectionViewScrollPositionRight:
|
||||
contentOffset.x = offset.max - collectionViewWidth + contentInset.right;
|
||||
break;
|
||||
case UICollectionViewScrollPositionCenteredHorizontally: {
|
||||
const CGFloat insets = (contentInset.left - contentInset.right) / 2.0;
|
||||
contentOffset.x = offsetMid - collectionViewWidth / 2.0 - insets;
|
||||
break;
|
||||
}
|
||||
case UICollectionViewScrollPositionLeft:
|
||||
case UICollectionViewScrollPositionNone:
|
||||
case UICollectionViewScrollPositionTop:
|
||||
case UICollectionViewScrollPositionBottom:
|
||||
case UICollectionViewScrollPositionCenteredVertically:
|
||||
contentOffset.x = offset.min - contentInset.left;
|
||||
break;
|
||||
}
|
||||
const CGFloat maxOffsetX = collectionView.contentSize.width - collectionView.frame.size.width + contentInset.right;
|
||||
const CGFloat minOffsetX = -contentInset.left;
|
||||
contentOffset.x += additionalOffset;
|
||||
contentOffset.x = MIN(contentOffset.x, maxOffsetX);
|
||||
contentOffset.x = MAX(contentOffset.x, minOffsetX);
|
||||
break;
|
||||
}
|
||||
case UICollectionViewScrollDirectionVertical: {
|
||||
switch (scrollPosition) {
|
||||
case UICollectionViewScrollPositionBottom:
|
||||
contentOffset.y = offset.max - collectionViewHeight + contentInset.bottom;
|
||||
break;
|
||||
case UICollectionViewScrollPositionCenteredVertically: {
|
||||
const CGFloat insets = (contentInset.top - contentInset.bottom) / 2.0;
|
||||
contentOffset.y = offsetMid - collectionViewHeight / 2.0 - insets;
|
||||
break;
|
||||
}
|
||||
case UICollectionViewScrollPositionTop:
|
||||
case UICollectionViewScrollPositionNone:
|
||||
case UICollectionViewScrollPositionLeft:
|
||||
case UICollectionViewScrollPositionRight:
|
||||
case UICollectionViewScrollPositionCenteredHorizontally:
|
||||
contentOffset.y = offset.min - contentInset.top;
|
||||
break;
|
||||
}
|
||||
// If we don't call [collectionView layoutIfNeeded], the collectionView.contentSize does not get updated.
|
||||
// So lets use the layout object, since it should have been updated by now.
|
||||
const CGFloat maxHeight = collectionView.collectionViewLayout.collectionViewContentSize.height;
|
||||
const CGFloat maxOffsetY = maxHeight - collectionView.frame.size.height + contentInset.bottom;
|
||||
const CGFloat minOffsetY = -contentInset.top;
|
||||
contentOffset.y += additionalOffset;
|
||||
contentOffset.y = MIN(contentOffset.y, maxOffsetY);
|
||||
contentOffset.y = MAX(contentOffset.y, minOffsetY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[collectionView setContentOffset:contentOffset animated:animated];
|
||||
}
|
||||
|
||||
- (nullable NSIndexPath *)indexPathForFirstVisibleItem {
|
||||
const CGPoint contentOffset = self.collectionView.contentOffset;
|
||||
const UIEdgeInsets contentInset = self.collectionView.contentInset;
|
||||
const CGPoint point = CGPointMake(contentOffset.x + contentInset.left, contentOffset.y + contentInset.top);
|
||||
return [self.collectionView indexPathForItemAtPoint:point];
|
||||
}
|
||||
|
||||
- (CGFloat)offsetForFirstVisibleItemWithScrollDirection:(UICollectionViewScrollDirection)scrollDirection {
|
||||
NSIndexPath *const indexPath = [self indexPathForFirstVisibleItem];
|
||||
if (indexPath) {
|
||||
const OffsetRange offset = [self _offsetRangeForIndexPath:indexPath supplementaryKinds:nil scrollDirection:scrollDirection];
|
||||
switch (scrollDirection) {
|
||||
case UICollectionViewScrollDirectionHorizontal:
|
||||
return self.collectionView.contentInset.left + self.collectionView.contentOffset.x - offset.min;
|
||||
case UICollectionViewScrollDirectionVertical:
|
||||
return self.collectionView.contentInset.top + self.collectionView.contentOffset.y - offset.min;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
- (OffsetRange)_offsetRangeForIndexPath:(NSIndexPath *)indexPath
|
||||
supplementaryKinds:(nullable NSArray<NSString *> *)supplementaryKinds
|
||||
scrollDirection:(UICollectionViewScrollDirection)scrollDirection {
|
||||
const NSUInteger section = indexPath.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
|
||||
NSMutableArray<UICollectionViewLayoutAttributes *> *attributes = nil;
|
||||
|
||||
const NSInteger numberOfItems = [collectionView numberOfItemsInSection:section];
|
||||
const NSInteger numberOfItems = [self.collectionView numberOfItemsInSection:section];
|
||||
if (numberOfItems > 0) {
|
||||
attributes = [self _layoutAttributesForItemAndSupplementaryViewAtIndexPath:indexPathFirstElement
|
||||
attributes = [self _layoutAttributesForItemAndSupplementaryViewAtIndexPath:indexPath
|
||||
supplementaryKinds:supplementaryKinds].mutableCopy;
|
||||
|
||||
if (numberOfItems > 1) {
|
||||
|
|
@ -241,7 +341,7 @@
|
|||
} else {
|
||||
NSMutableArray *supplementaryAttributes = [NSMutableArray new];
|
||||
for (NSString* supplementaryKind in supplementaryKinds) {
|
||||
UICollectionViewLayoutAttributes *supplementaryAttribute = [self _layoutAttributesForSupplementaryViewOfKind:supplementaryKind atIndexPath:indexPathFirstElement];
|
||||
UICollectionViewLayoutAttributes *supplementaryAttribute = [self _layoutAttributesForSupplementaryViewOfKind:supplementaryKind atIndexPath:indexPath];
|
||||
if (supplementaryAttribute != nil) {
|
||||
[supplementaryAttributes addObject: supplementaryAttribute];
|
||||
}
|
||||
|
|
@ -249,8 +349,7 @@
|
|||
attributes = supplementaryAttributes;
|
||||
}
|
||||
|
||||
CGFloat offsetMin = 0.0;
|
||||
CGFloat offsetMax = 0.0;
|
||||
OffsetRange offset = (OffsetRange) { .min = 0, .max = 0 };
|
||||
for (UICollectionViewLayoutAttributes *attribute in attributes) {
|
||||
const CGRect frame = attribute.frame;
|
||||
CGFloat originMin;
|
||||
|
|
@ -267,77 +366,16 @@
|
|||
}
|
||||
|
||||
// find the minimum origin value of all the layout attributes
|
||||
if (attribute == attributes.firstObject || originMin < offsetMin) {
|
||||
offsetMin = originMin;
|
||||
if (attribute == attributes.firstObject || originMin < offset.min) {
|
||||
offset.min = originMin;
|
||||
}
|
||||
// find the maximum end value of all the layout attributes
|
||||
if (attribute == attributes.firstObject || endMax > offsetMax) {
|
||||
offsetMax = endMax;
|
||||
if (attribute == attributes.firstObject || endMax > offset.max) {
|
||||
offset.max = 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.ig_contentInset;
|
||||
CGPoint contentOffset = collectionView.contentOffset;
|
||||
switch (scrollDirection) {
|
||||
case UICollectionViewScrollDirectionHorizontal: {
|
||||
switch (scrollPosition) {
|
||||
case UICollectionViewScrollPositionRight:
|
||||
contentOffset.x = offsetMax - collectionViewWidth + contentInset.right;
|
||||
break;
|
||||
case UICollectionViewScrollPositionCenteredHorizontally: {
|
||||
const CGFloat insets = (contentInset.left - contentInset.right) / 2.0;
|
||||
contentOffset.x = offsetMid - collectionViewWidth / 2.0 - insets;
|
||||
break;
|
||||
}
|
||||
case UICollectionViewScrollPositionLeft:
|
||||
case UICollectionViewScrollPositionNone:
|
||||
case UICollectionViewScrollPositionTop:
|
||||
case UICollectionViewScrollPositionBottom:
|
||||
case UICollectionViewScrollPositionCenteredVertically:
|
||||
contentOffset.x = offsetMin - contentInset.left;
|
||||
break;
|
||||
}
|
||||
const CGFloat maxOffsetX = collectionView.contentSize.width - collectionView.frame.size.width + contentInset.right;
|
||||
const CGFloat minOffsetX = -contentInset.left;
|
||||
contentOffset.x += additionalOffset;
|
||||
contentOffset.x = MIN(contentOffset.x, maxOffsetX);
|
||||
contentOffset.x = MAX(contentOffset.x, minOffsetX);
|
||||
break;
|
||||
}
|
||||
case UICollectionViewScrollDirectionVertical: {
|
||||
switch (scrollPosition) {
|
||||
case UICollectionViewScrollPositionBottom:
|
||||
contentOffset.y = offsetMax - collectionViewHeight + contentInset.bottom;
|
||||
break;
|
||||
case UICollectionViewScrollPositionCenteredVertically: {
|
||||
const CGFloat insets = (contentInset.top - contentInset.bottom) / 2.0;
|
||||
contentOffset.y = offsetMid - collectionViewHeight / 2.0 - insets;
|
||||
break;
|
||||
}
|
||||
case UICollectionViewScrollPositionTop:
|
||||
case UICollectionViewScrollPositionNone:
|
||||
case UICollectionViewScrollPositionLeft:
|
||||
case UICollectionViewScrollPositionRight:
|
||||
case UICollectionViewScrollPositionCenteredHorizontally:
|
||||
contentOffset.y = offsetMin - contentInset.top;
|
||||
break;
|
||||
}
|
||||
// If we don't call [collectionView layoutIfNeeded], the collectionView.contentSize does not get updated.
|
||||
// So lets use the layout object, since it should have been updated by now.
|
||||
const CGFloat maxHeight = collectionView.collectionViewLayout.collectionViewContentSize.height;
|
||||
const CGFloat maxOffsetY = maxHeight - collectionView.frame.size.height + contentInset.bottom;
|
||||
const CGFloat minOffsetY = -contentInset.top;
|
||||
contentOffset.y += additionalOffset;
|
||||
contentOffset.y = MIN(contentOffset.y, maxOffsetY);
|
||||
contentOffset.y = MAX(contentOffset.y, minOffsetY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[collectionView setContentOffset:contentOffset animated:animated];
|
||||
return offset;
|
||||
}
|
||||
|
||||
#pragma mark - Editing
|
||||
|
|
|
|||
|
|
@ -928,6 +928,241 @@
|
|||
XCTAssertTrue(lastSection.wasDisplayed);
|
||||
}
|
||||
|
||||
- (void)test_whenScrolledVertically_thatIndexPathForFirstVisibleItemIsCorrect {
|
||||
self.dataSource.objects = @[@1, @2, @3];
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
XCTAssertEqual([self.collectionView numberOfSections], 3);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:0]);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 8) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:0]);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 12) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:1]);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 35) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:2]);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 40) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:1 inSection:2]);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 59) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:2 inSection:2]);
|
||||
}
|
||||
|
||||
- (void)test_whenScrolledVerticallyWithContentInset_thatIndexPathForFirstVisibleItemIsCorrect {
|
||||
const CGFloat inset = 5;
|
||||
self.collectionView.contentInset = UIEdgeInsetsMake(inset, 0, inset, 0);
|
||||
self.dataSource.objects = @[@1, @2, @3];
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
XCTAssertEqual([self.collectionView numberOfSections], 3);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 0 - inset) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:0]);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 8 - inset) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:0]);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 12 - inset) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:1]);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 35 - inset) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:2]);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 40 - inset) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:1 inSection:2]);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 59 - inset) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:2 inSection:2]);
|
||||
}
|
||||
|
||||
- (void)test_whenScrolledHorizontallyWithSingleRow_thatIndexPathForFirstVisibleItemIsCorrect {
|
||||
self.dataSource.objects = @[@1, @2, @3, @4];
|
||||
self.layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
self.collectionView.frame = CGRectMake(0, 0, 300, 10);
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
XCTAssertEqual([self.collectionView numberOfSections], 4);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:0]);
|
||||
[self.collectionView setContentOffset:CGPointMake(80, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:0]);
|
||||
[self.collectionView setContentOffset:CGPointMake(120, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:1]);
|
||||
[self.collectionView setContentOffset:CGPointMake(350, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:2]);
|
||||
[self.collectionView setContentOffset:CGPointMake(400, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:1 inSection:2]);
|
||||
[self.collectionView setContentOffset:CGPointMake(590, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:2 inSection:2]);
|
||||
}
|
||||
|
||||
- (void)test_whenScrolledHorizontallyWithSingleRowWithContentInset_thatIndexPathForFirstVisibleItemIsCorrect {
|
||||
const CGFloat inset = 172;
|
||||
self.collectionView.contentInset = UIEdgeInsetsMake(0, inset, 0, inset);
|
||||
self.dataSource.objects = @[@1, @2, @3, @4];
|
||||
self.layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
self.collectionView.frame = CGRectMake(0, 0, 300, 10);
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
XCTAssertEqual([self.collectionView numberOfSections], 4);
|
||||
[self.collectionView setContentOffset:CGPointMake(0 - inset, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:0]);
|
||||
[self.collectionView setContentOffset:CGPointMake(80 - inset, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:0]);
|
||||
[self.collectionView setContentOffset:CGPointMake(120 - inset, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:1]);
|
||||
[self.collectionView setContentOffset:CGPointMake(350 - inset, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:2]);
|
||||
[self.collectionView setContentOffset:CGPointMake(400 - inset, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:1 inSection:2]);
|
||||
[self.collectionView setContentOffset:CGPointMake(590 - inset, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:2 inSection:2]);
|
||||
}
|
||||
|
||||
- (void)test_whenScrolledHorizontallyWithStackedSections_thatIndexPathForFirstVisibleItemIsCorrect {
|
||||
self.dataSource.objects = @[@1, @2, @3, @4, @5, @6];
|
||||
self.layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
XCTAssertEqual([self.collectionView numberOfSections], 6);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:0]);
|
||||
[self.collectionView setContentOffset:CGPointMake(80, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:0]);
|
||||
[self.collectionView setContentOffset:CGPointMake(120, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:1]);
|
||||
[self.collectionView setContentOffset:CGPointMake(350, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:3]);
|
||||
[self.collectionView setContentOffset:CGPointMake(400, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:4]);
|
||||
[self.collectionView setContentOffset:CGPointMake(590, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter indexPathForFirstVisibleItem], [NSIndexPath indexPathForItem:0 inSection:5]);
|
||||
}
|
||||
|
||||
- (void)test_whenScrolledVertically_thatOffsetForFirstVisibleItemIsCorrect {
|
||||
self.dataSource.objects = @[@1, @2, @3, @4, @5, @6];
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
XCTAssertEqual([self.collectionView numberOfSections], 6);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 0);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 8) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 8);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 12) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 2);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 35) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 5);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 40) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 0);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 59) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 9);
|
||||
}
|
||||
|
||||
- (void)test_whenScrolledVerticallyWithContentInset_thatOffsetForFirstVisibleItemIsCorrect {
|
||||
const CGFloat inset = 5;
|
||||
self.collectionView.contentInset = UIEdgeInsetsMake(inset, 0, inset, 0);
|
||||
self.dataSource.objects = @[@1, @2, @3, @4, @5, @6];
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
XCTAssertEqual([self.collectionView numberOfSections], 6);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 0 - inset) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 0);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 8 - inset) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 8);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 12 - inset) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 2);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 35 - inset) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 5);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 40 - inset) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 0);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 59 - inset) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 9);
|
||||
}
|
||||
|
||||
- (void)test_whenScrolledHorizontallyWithSingleRow_thatOffsetForFirstVisibleItemIsCorrect {
|
||||
self.dataSource.objects = @[@1, @2, @3, @4];
|
||||
self.layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
self.collectionView.frame = CGRectMake(0, 0, 300, 10);
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
XCTAssertEqual([self.collectionView numberOfSections], 4);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 0);
|
||||
[self.collectionView setContentOffset:CGPointMake(80, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 80);
|
||||
[self.collectionView setContentOffset:CGPointMake(120, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 20);
|
||||
[self.collectionView setContentOffset:CGPointMake(350, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 50);
|
||||
[self.collectionView setContentOffset:CGPointMake(400, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 0);
|
||||
[self.collectionView setContentOffset:CGPointMake(599, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 99);
|
||||
}
|
||||
|
||||
- (void)test_whenScrolledHorizontallyWithSingleRowWithContentInset_thatOffsetForFirstVisibleItemIsCorrect {
|
||||
const CGFloat inset = 172;
|
||||
self.collectionView.contentInset = UIEdgeInsetsMake(0, inset, 0, inset);
|
||||
self.dataSource.objects = @[@1, @2, @3, @4];
|
||||
self.layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
self.collectionView.frame = CGRectMake(0, 0, 300, 10);
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
XCTAssertEqual([self.collectionView numberOfSections], 4);
|
||||
[self.collectionView setContentOffset:CGPointMake(0 - inset, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 0);
|
||||
[self.collectionView setContentOffset:CGPointMake(80 - inset, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 80);
|
||||
[self.collectionView setContentOffset:CGPointMake(120 - inset, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 20);
|
||||
[self.collectionView setContentOffset:CGPointMake(350 - inset, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 50);
|
||||
[self.collectionView setContentOffset:CGPointMake(400 - inset, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 0);
|
||||
[self.collectionView setContentOffset:CGPointMake(599 - inset, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 99);
|
||||
}
|
||||
|
||||
- (void)test_whenScrolledHorizontallyWithStackedSections_thatOffsetForFirstVisibleItemIsCorrect {
|
||||
self.dataSource.objects = @[@1, @2, @3, @4, @5, @6];
|
||||
self.layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
XCTAssertEqual([self.collectionView numberOfSections], 6);
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 0);
|
||||
[self.collectionView setContentOffset:CGPointMake(80, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 80);
|
||||
[self.collectionView setContentOffset:CGPointMake(120, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 20);
|
||||
[self.collectionView setContentOffset:CGPointMake(350, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 50);
|
||||
[self.collectionView setContentOffset:CGPointMake(400, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 0);
|
||||
[self.collectionView setContentOffset:CGPointMake(599, 0) animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 99);
|
||||
}
|
||||
|
||||
- (void)test_whenScrollToIndexPathWithAdditionalOffsetVerticially_thatOffsetForFirstVisibleItemIsCorrect {
|
||||
const CGFloat inset = 5;
|
||||
self.collectionView.contentInset = UIEdgeInsetsMake(inset, 0, inset, 0);
|
||||
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 scrollPosition:UICollectionViewScrollPositionNone additionalOffset:0 animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 0);
|
||||
[self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone additionalOffset:7 animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 7);
|
||||
[self.adapter scrollToObject:@3 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone additionalOffset:0 animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 0);
|
||||
[self.adapter scrollToObject:@3 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone additionalOffset:3 animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 3);
|
||||
[self.adapter scrollToObject:@4 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone additionalOffset:9 animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionVertical], 9);
|
||||
}
|
||||
|
||||
- (void)test_whenScrollToIndexPathWithAdditionalOffsetHorizontally_thatOffsetForFirstVisibleItemIsCorrect {
|
||||
const CGFloat inset = 172;
|
||||
self.collectionView.contentInset = UIEdgeInsetsMake(0, inset, 0, inset);
|
||||
self.dataSource.objects = @[@1, @2, @3, @4, @5, @6];
|
||||
self.layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
XCTAssertEqual([self.collectionView numberOfSections], 6);
|
||||
[self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionNone additionalOffset:0 animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 0);
|
||||
[self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionNone additionalOffset:73 animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 73);
|
||||
[self.adapter scrollToObject:@3 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionNone additionalOffset:0 animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 0);
|
||||
[self.adapter scrollToObject:@3 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionNone additionalOffset:36 animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 36);
|
||||
[self.adapter scrollToObject:@4 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionNone additionalOffset:99 animated:NO];
|
||||
XCTAssertEqual([self.adapter offsetForFirstVisibleItemWithScrollDirection:UICollectionViewScrollDirectionHorizontal], 99);
|
||||
}
|
||||
|
||||
- (void)test_whenQueryingIndexPath_withOOBSectionController_thatNilReturned {
|
||||
self.dataSource.objects = @[@0, @1, @2];
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
|
|
|
|||
Loading…
Reference in a new issue