How do you set the duration for UICollectionView Animations?

change CALayer's speed

@implementation Cell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
    self.layer.speed =0.2;//default speed  is 1
}
return self;
}

After trying [CATransaction setAnimationDuration:] and [UIView setAnimationDuration:] in every possible phase of the layout process without success, I figured out a somewhat hacky way to change the duration of cell animations created by UICollectionView that doesn't rely on private API's.

You can use CALayer's speed property to change the relative media timing of animations performed on a given layer. For this to work with UICollectionView, you can change layer.speed to something less than 1 on the cell's layer. Obviously it's not great to have the cell's layer ALWAYS have a non-unity animation speed, so one option is to dispatch an NSNotification when preparing for cell animations, to which your cells subscribe, that will change the layer speed, and then change it back at an appropriate time after the animations are finished.

I don't recommend using this approach as a long-term solution as it's pretty roundabout, but it does work. Hopefully Apple will expose more options for UICollectionView animations in the future.


Building on @rotava's answer, you can temporarily set the animation speed by using a batch update of the collection view:

[self.collectionView performBatchUpdates:^{
    [self.collectionView.viewForBaselineLayout.layer setSpeed:0.2];
    [self.collectionView insertItemsAtIndexPaths: insertedIndexPaths];
} completion:^(BOOL finished) {
    [self.collectionView.viewForBaselineLayout.layer setSpeed:1];
}];

To solve problem without hack that was proposed in the answer by gavrix you could subclass UICollectionViewLayoutAttributes with new property CABasicAnimation *transformAnimation, than create custom transformation with a suitable duration and assign it to attributes in initialLayoutAttributesForAppearingItemAtIndexPath, then in UICollectionViewCell apply the attributes as needed:

@interface AnimationCollectionViewLayoutAttributes : UICollectionViewLayoutAttributes
@property (nonatomic, strong)  CABasicAnimation *transformAnimation;
@end

@implementation AnimationCollectionViewLayoutAttributes
- (id)copyWithZone:(NSZone *)zone
{
    AnimationCollectionViewLayoutAttributes *attributes = [super copyWithZone:zone];
    attributes.transformAnimation = _transformAnimation;
    return attributes;
}

- (BOOL)isEqual:(id)other {
    if (other == self) {
        return YES;
    }
    if (!other || ![[other class] isEqual:[self class]]) {
        return NO;
    }
    if ([(( AnimationCollectionViewLayoutAttributes *) other) transformAnimation] != [self transformAnimation]) {
        return NO;
    }

    return YES;
}
@end

In Layout class

- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath {
    AnimationCollectionViewLayoutAttributes* attributes = (AnimationCollectionViewLayoutAttributes* )[super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath];

    CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
    transformAnimation.duration = 1.0f;
    CGFloat height = [self collectionViewContentSize].height;

    transformAnimation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0, 2*height, height)];
    transformAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0, attributes.bounds.origin.y, 0)];
    transformAnimation.removedOnCompletion = NO;
    transformAnimation.fillMode = kCAFillModeForwards;
    attributes.transformAnimation = transformAnimation;
    return attributes;
}

+ (Class)layoutAttributesClass { 
    return [AnimationCollectionViewLayoutAttributes class]; 
}

then in UICollectionViewCell apply the attributes

- (void) applyLayoutAttributes:(AnimationCollectionViewLayoutAttributes *)layoutAttributes
{
    [[self layer] addAnimation:layoutAttributes.transformAnimation forKey:@"transform"];
}