Skip to content

Instantly share code, notes, and snippets.

@sdgandhi
Last active August 29, 2015 14:21
Show Gist options
  • Save sdgandhi/c0bcb4e8441393854277 to your computer and use it in GitHub Desktop.
Save sdgandhi/c0bcb4e8441393854277 to your computer and use it in GitHub Desktop.
Paged UICollectionViewFlowLayout with snapping and centering for arbitrary items
- (CGSize)collectionViewContentSize
{
CGSize size = [super collectionViewContentSize];
CGSize cvSize = self.collectionView.frame.size;
CGSize newSize = CGSizeMake(size.width, size.height + ((cvSize.height/2) - (self.itemSize.height/2)));
return newSize;
}
// Vertical scrolling
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
CGFloat offSetAdjustment = MAXFLOAT;
CGFloat verticalCenter = (CGFloat)(proposedContentOffset.y + (self.collectionView.bounds.size.height / 2.0));
CGRect targetRect = CGRectMake(0.0, proposedContentOffset.y, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);
NSArray *array = [self layoutAttributesForElementsInRect:targetRect];
UICollectionViewLayoutAttributes *currentAttributes;
for (UICollectionViewLayoutAttributes *layoutAttributes in array) {
if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
CGFloat itemVerticalCenter = layoutAttributes.center.y;
if (ABS(itemVerticalCenter - verticalCenter) < ABS(offSetAdjustment)) {
currentAttributes = layoutAttributes;
offSetAdjustment = itemVerticalCenter - verticalCenter;
}
}
}
CGFloat nextOffset = proposedContentOffset.y + offSetAdjustment;
proposedContentOffset.y = nextOffset;
CGFloat deltaY = proposedContentOffset.y - self.collectionView.contentOffset.y;
CGFloat velY = velocity.y;
// detection form gist.github.com/rkeniger/7687301
// based on http://stackoverflow.com/a/14291208/740949
if (deltaY == 0.0 || velY == 0 || (velY > 0.0 && deltaY > 0.0) || (velY < 0.0 && deltaY < 0.0)) {
} else if (velocity.y > 0.0) {
for (UICollectionViewLayoutAttributes *layoutAttributes in array) {
if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
CGFloat itemVerticalCenter = layoutAttributes.center.y;
if (itemVerticalCenter > proposedContentOffset.y) {
proposedContentOffset.y = nextOffset + (currentAttributes.frame.size.height / 2) + (layoutAttributes.frame.size.height / 2);
break;
}
}
}
} else if (velocity.y< 0.0) {
for (UICollectionViewLayoutAttributes *layoutAttributes in array) {
if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
CGFloat itemVerticalCenter = layoutAttributes.center.y;
if (itemVerticalCenter > proposedContentOffset.y) {
proposedContentOffset.y = nextOffset - ((currentAttributes.frame.size.height / 2) + (layoutAttributes.frame.size.height / 2));
break;
}
}
}
}
proposedContentOffset.x = 0.0;
return proposedContentOffset;
}
// Horizontal scrolling
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
CGFloat offSetAdjustment = MAXFLOAT;
CGFloat horizontalCenter = (CGFloat)(proposedContentOffset.x + (self.collectionView.bounds.size.width / 2.0));
CGRect targetRect = CGRectMake(proposedContentOffset.x, 0.0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);
NSArray *array = [self layoutAttributesForElementsInRect:targetRect];
UICollectionViewLayoutAttributes *currentAttributes;
for (UICollectionViewLayoutAttributes *layoutAttributes in array) {
if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
CGFloat itemHorizontalCenter = layoutAttributes.center.x;
if (ABS(itemHorizontalCenter - horizontalCenter) < ABS(offSetAdjustment)) {
currentAttributes = layoutAttributes;
offSetAdjustment = itemHorizontalCenter - horizontalCenter;
}
}
}
CGFloat nextOffset = proposedContentOffset.x + offSetAdjustment;
proposedContentOffset.x = nextOffset;
CGFloat deltaX = proposedContentOffset.x - self.collectionView.contentOffset.x;
CGFloat velX = velocity.x;
// detection form gist.github.com/rkeniger/7687301
// based on http://stackoverflow.com/a/14291208/740949
if (deltaX == 0.0 || velX == 0 || (velX > 0.0 && deltaX > 0.0) || (velX < 0.0 && deltaX < 0.0)) {
} else if (velocity.x > 0.0) {
for (UICollectionViewLayoutAttributes *layoutAttributes in array) {
if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
CGFloat itemHorizontalCenter = layoutAttributes.center.x;
if (itemHorizontalCenter > proposedContentOffset.x) {
proposedContentOffset.x = nextOffset + (currentAttributes.frame.size.width / 2) + (layoutAttributes.frame.size.width / 2);
break;
}
}
}
} else if (velocity.x < 0.0) {
for (UICollectionViewLayoutAttributes *layoutAttributes in array) {
if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
CGFloat itemHorizontalCenter = layoutAttributes.center.x;
if (itemHorizontalCenter > proposedContentOffset.x) {
proposedContentOffset.x = nextOffset - ((currentAttributes.frame.size.width / 2) + (layoutAttributes.frame.size.width / 2));
break;
}
}
}
}
proposedContentOffset.y = 0.0;
return proposedContentOffset;
}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment