17

I'm sometimes scroll to the left of a cell like this:

collectionView.scrollToItem(
    at: IndexPath(row: 5, section: 0),
    at: .left, // TODO: Left ignores inset
    animated: true
)

This is how it starts out before scrollToItem implemented:

enter image description here

However, when I try to use scroll to item, it sticks the cell to the edge instead of considering the inset:

enter image description here

Is there an easy way to fix collectionView.scrollToItem to accommodate the insets?

TruMan1
  • 33,665
  • 59
  • 184
  • 335
  • try **.bottom** from **.left** – iOS Geek Jun 26 '18 at 04:41
  • Good idea, but didn't work for me unfortunately. I tried: "collectionView.scrollToItem(at: indexPath, at: [.bottom, .left], animated: true)". I also tried difference variations like [.top, .left], .bottom, .top, [.left, .bottom], etc. – TruMan1 Jun 26 '18 at 10:48
  • 1. Is it Vertical Or Horizontal in Direction? 2. What is the size of your cell? e.g. One Item is being displayed at a time or two items or n number – Sahil Manchanda Jul 06 '18 at 05:18

5 Answers5

25

You can use the regular method collectionView.scrollToItem if you set your inset in collectionView.contentInset instead of layout.sectionInset.

7

Objective-C

   /**
     Assumptions:
     1. Your collection view scrolls horizontally
     2. You are using UICollectionViewFlowLayout to layout you collection view

     @param indexPath IndexPath to scroll to
     @param animated Toggle animations
     */
    - (void)scrollToIndexPathPreservingLeftInset:(NSIndexPath *)indexPath animated:(BOOL)animated {
        UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)collectionView.collectionViewLayout;
        CGFloat sectionLeftInset = layout.sectionInset.left;
        UICollectionViewLayoutAttributes *attri = [layout layoutAttributesForItemAtIndexPath:indexPath];
        [collectionView setContentOffset:CGPointMake(attri.frame.origin.x - sectionLeftInset, 0) animated:animated];
    }

Swift (not verified syntactically)

func scroll(toIndexPathPreservingLeftInset indexPath: IndexPath, animated: Bool) {
    let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
    let sectionLeftInset = layout.sectionInset.left
    var attri = layout.layoutAttributesForItem(at: aPath)
    collectionView.setContentOffset(CGPoint(x: (attri?.frame.origin.x - sectionLeftInset), y: 0), animated: animated)
}

Sample gif

BangOperator
  • 4,377
  • 2
  • 24
  • 38
6

Set conentInset value to your collectionView like this:

myCollectionView.contentInset = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)

and then add this line:

 if #available(iOS 11, *) {
            self.myCollectionView.contentInsetAdjustmentBehavior =     .never
        }

then scrolltoItem works by respecting the insets of collectionView.

Frankenxtein
  • 483
  • 7
  • 18
  • 1
    This is the up-to-date correct answer (tested on iOS 13). Prior to iOS 11 `collectionView.scrollToItem()` was respecting the collectionview insets, but on iOS 11 and above, we need to set `contentInsetAdjustmentBehavior = .never` – ElectroBuddha Sep 04 '19 at 18:04
2

Since each cell's frame takes into account its section inset, you may as well use scrollRectToVisible(_:animated:).

let cell = collectionView.cellForItem(at: indexPath)!
collectionView.scrollRectToVisible(cell.frame, animated: true)

And since it is a frame we're working on, you can fine tune some desired offset to that frame.

nyrd
  • 478
  • 3
  • 9
  • I thought this would work, but it's not doesn't anything at all in my case. I believe it because it needs contentSize set but I'm using itemSize. – TruMan1 Jun 30 '18 at 06:20
  • cellForItem requires that the cell be visible, so won't work if you want to scroll to an index path that isn't visible. – Matt Comi Jul 08 '19 at 04:05
  • 2
    In iOS 15+, this would work since cellForItem returns non-visible cells. Pre iOS-15, non visible cells would return nil. – Vadoff Jul 29 '21 at 21:47
1

In case anyone else stumbles on this looking to scroll to the beginning of a horizontal collection view, while considering the section insets, I was able to get this to work by doing the following (in Swift 5.2.4). This solution takes advantage of the fact that UICollectionViews are UIScrollViews:

    (collectionView as UIScrollView).setContentOffset(.zero, animated: true)
Campbell_Souped
  • 871
  • 10
  • 22