Search code examples
objective-cmacoscocoaappkitnscollectionview

How to animate NSCollectionView's scrollToIndexPaths:scrollPosition:?


I'm trying to animate NSCollectionView's scrollToIndexPaths:scrollPosition:, which according to the documentation can be achieved if this message is sent to the collection view's animator proxy. However, I can't get it to work.

I've set up a very simple project that includes nothing but a collection view and creates 1000 100x100 items. A simple action increments the visible index path by 50 and tries to scroll to it. My scrolling code looks like:

- (IBAction)increment:(id)sender {
  NSIndexPath *visibleIndexPath = [[self.collectionView indexPathsForVisibleItems] anyObject];
  NSIndexPath *toIndexPath = [NSIndexPath indexPathForItem:visibleIndexPath.item + 50 inSection:visibleIndexPath.section];
  [self.collectionView.animator scrollToItemsAtIndexPaths:[NSSet setWithObject:toIndexPath] scrollPosition:NSCollectionViewScrollPositionCenteredHorizontally];
}

This jumps the collection view to the target index path but does not animate. I've ensured that the scroll view is layer backed too, based on some of the other threads I've found on this:

enter image description here

The only other code in the project are a few lines that set up the collection view and flow layout in viewDidLoad::

  // Do any additional setup after loading the view.
  NSCollectionViewFlowLayout *flowLayout = [[NSCollectionViewFlowLayout alloc] init];
  flowLayout.itemSize = CGSizeMake(100.f, 100.f);
  flowLayout.scrollDirection = NSCollectionViewScrollDirectionHorizontal;
  self.collectionView.collectionViewLayout = flowLayout;

  [self.collectionView registerClass:[CollectionViewItem class] forItemWithIdentifier:@"identifier"];

Has anyone been able to animate using scrollToIndexPaths:scrollPosition:? The documentation makes it sound obvious but I can't get it to work.


Solution

  • I faced with the same issue and spent a while to fix it. They have a concept of implicit animations which take care non-property changing code. I.e. looks like animator will animate certain properties but not other layout changes. To allow those "other" changes be animated, you have to set allow implicit animations to the current animation context. Here is my working code:

    let ctx = NSAnimationContext.current()
    ctx.allowsImplicitAnimation = true
    
    collectionView.animator().scrollToItemsAtIndexPaths(Set<NSIndexPath>(arrayLiteral: nextPath), scrollPosition: .TrailingEdge)
    

    Note: I edited the snippet to support newer Swift syntax.