Skip to content

Commit

Permalink
Fix over-scrolling issue in IGListAdapter scrollToObject: method
Browse files Browse the repository at this point in the history
Summary:
UIScrollView can over-scroll, if content offset is too small or too large.

Providing methods to help calculate safe content offsets, given the desired values. Use the safe content offsets in IGListAdapter.

Reviewed By: rnystrom

Differential Revision: D5312473

fbshipit-source-id: d882948940ce08c48f5ff0ab8d997591f62915a8
  • Loading branch information
Chen (Bert) Li authored and facebook-github-bot committed Jun 29, 2017
1 parent e58a44c commit 1d926d9
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 8 deletions.
14 changes: 12 additions & 2 deletions Source/IGListAdapter.m
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ - (void)scrollToObject:(id)object
const UIEdgeInsets contentInset = collectionView.contentInset;
CGPoint contentOffset = collectionView.contentOffset;
switch (scrollDirection) {
case UICollectionViewScrollDirectionHorizontal:
case UICollectionViewScrollDirectionHorizontal: {
switch (scrollPosition) {
case UICollectionViewScrollPositionRight:
contentOffset.x = offsetMax - collectionViewWidth - contentInset.left;
Expand All @@ -238,8 +238,13 @@ - (void)scrollToObject:(id)object
contentOffset.x = offsetMin - contentInset.left;
break;
}
const CGFloat maxOffsetX = collectionView.contentSize.width - collectionView.frame.size.width + collectionView.contentInset.right;
const CGFloat minOffsetX = -collectionView.contentInset.left;
contentOffset.x = MIN(contentOffset.x, maxOffsetX);
contentOffset.x = MAX(contentOffset.x, minOffsetX);
break;
case UICollectionViewScrollDirectionVertical:
}
case UICollectionViewScrollDirectionVertical: {
switch (scrollPosition) {
case UICollectionViewScrollPositionBottom:
contentOffset.y = offsetMax - collectionViewHeight - contentInset.top;
Expand All @@ -257,7 +262,12 @@ - (void)scrollToObject:(id)object
contentOffset.y = offsetMin - contentInset.top;
break;
}
const CGFloat maxOffsetY = collectionView.contentSize.height - collectionView.frame.size.height + collectionView.contentInset.bottom;
const CGFloat minOffsetY = -collectionView.contentInset.top;
contentOffset.y = MIN(contentOffset.y, maxOffsetY);
contentOffset.y = MAX(contentOffset.y, minOffsetY);
break;
}
}

[collectionView setContentOffset:contentOffset animated:animated];
Expand Down
18 changes: 12 additions & 6 deletions Tests/IGListAdapterTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,8 @@ - (void)test_whenScrollVerticallyToItem {
[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 scrollPosition:UICollectionViewScrollPositionNone animated:NO];
IGAssertEqualPoint([self.collectionView contentOffset], 0, 150);
// Content height minus collection view height is 110, can't scroll more than that
IGAssertEqualPoint([self.collectionView contentOffset], 0, 110);
[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];
Expand All @@ -649,7 +650,8 @@ - (void)test_whenScrollHorizontallyToItem {
[self.adapter scrollToObject:@3 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionNone animated:NO];
IGAssertEqualPoint([self.collectionView contentOffset], 30, 0);
[self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionNone animated:NO];
IGAssertEqualPoint([self.collectionView contentOffset], 150, 0);
// Content width minus collection view width is 110, can't scroll more than that
IGAssertEqualPoint([self.collectionView contentOffset], 110, 0);
[self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
IGAssertEqualPoint([self.collectionView contentOffset], 105, 0);
[self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionRight animated:NO];
Expand All @@ -676,7 +678,8 @@ - (void)test_whenScrollToItem_thatSupplementarySourceSupportsSingleHeader {
[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 scrollPosition:UICollectionViewScrollPositionNone animated:NO];
IGAssertEqualPoint([self.collectionView contentOffset], 0, 20);
// Content height smaller than collection view height, won't scroll
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
}

- (void)test_whenScrollToItem_thatSupplementarySourceSupportsHeaderAndFooter {
Expand All @@ -698,7 +701,8 @@ - (void)test_whenScrollToItem_thatSupplementarySourceSupportsHeaderAndFooter {
[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 scrollPosition:UICollectionViewScrollPositionNone animated:NO];
IGAssertEqualPoint([self.collectionView contentOffset], 0, 30);
// Content height smaller than collection view height, won't scroll
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
}

- (void)test_whenScrollVerticallyToItem_thatFeedIsEmpty {
Expand All @@ -719,9 +723,11 @@ - (void)test_whenScrollVerticallyToItem_thatItemNotInFeed {
[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 scrollPosition:UICollectionViewScrollPositionNone animated:NO];
IGAssertEqualPoint([self.collectionView contentOffset], 0, 10);
// Content height is smaller than collection view height, can't scroll
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
[self.adapter scrollToObject:@5 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
IGAssertEqualPoint([self.collectionView contentOffset], 0, 10);
// Content height is smaller than collection view height, can't scroll
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
}

- (void)test_whenQueryingIndexPath_withOOBSectionController_thatNilReturned {
Expand Down

0 comments on commit 1d926d9

Please sign in to comment.