Programmatically scroll to a supplementary view within UICollectionView Programmatically scroll to a supplementary view within UICollectionView ios ios

Programmatically scroll to a supplementary view within UICollectionView

You can not use scrollToItemAtIndexPath:atScrollPosition:animated for this.

Hopefully, they will add a new method like scrollToSupplementaryElementOfKind:atIndexPath: in the future, but for now, the only way is to manipulate the contentOffset directly.

The code below shows how to scroll header to be on top vertically with FlowLayout. You can do the same for horizontal scrolling, or use this idea for other layout types.

NSIndexPath *indexPath = ... // indexPath of your header, item must be 0CGFloat offsetY = [collectionView layoutAttributesForSupplementaryElementOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath].frame.origin.y;CGFloat contentInsetY =;CGFloat sectionInsetY = ((UICollectionViewFlowLayout *)collectionView.collectionViewLayout);[collectionView setContentOffset:CGPointMake(collectionView.contentOffset.x, offsetY - contentInsetY - sectionInsetY) animated:YES];

Note that if you have non-zero contentInset (as in iOS 7, when scroll views expand below bars) you need to subtract it from the offsetY, as shown. Same for sectionInset.


The code assumes that the layout is in prepared, "valid" state because it uses it to calculate the offset. The layout is prepared when the collection view presents its content.

The call to [_collectionView.collectionViewLayout prepareLayout] before the code above may help when you need to scroll the collection view which is not yet presented (from viewDidLoad say). The call to layoutIfNeeded (as @Vrasidas suggested in comments) should work too because it also prepares the layout.

Solution in Swift,

let section: Int = 0 // Topif let cv = self.collectionView {    cv.layoutIfNeeded()    let indexPath = IndexPath(row: 1, section: section)    if let attributes =  cv.layoutAttributesForSupplementaryElement(ofKind: UICollectionView.elementKindSectionHeader, at: indexPath) {        let topOfHeader = CGPoint(x: 0, y: attributes.frame.origin.y -        cv.setContentOffset(topOfHeader, animated: true)    }}

Props to Gene De Lisa:

// scroll to selected indexNSIndexPath* cellIndexPath = [NSIndexPath indexPathForItem:0 inSection:sectionIndex];UICollectionViewLayoutAttributes* attr = [self.collectionView.collectionViewLayout layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:cellIndexPath];UIEdgeInsets insets = self.collectionView.scrollIndicatorInsets;CGRect rect = attr.frame;rect.size = self.collectionView.frame.size;rect.size.height -= + insets.bottom;CGFloat offset = (rect.origin.y + rect.size.height) - self.collectionView.contentSize.height;if ( offset > 0.0 ) rect = CGRectOffset(rect, 0, -offset);[self.collectionView scrollRectToVisible:rect animated:YES];