Search code examples
iosanimationcore-animationobjective-c-blocksicarousel

Core animation calling completion function immediately


I'm trying to animate some stuff using the usual UIView class methods. I'm calling these animate methods in a method called by the popular iCarousel library. When I scroll the carousel, the animation immediately goes to its completion state and calls the completion function (ignoring the duration on the animation). The finished BOOL is true, so it doesn't look like the animation is being interrupted.

When I trigger these animations outside of iCarousel's delegate methods, they work. I'm not looking to fix iCarousel, nor do I presume something is broken with it. I'm more curious what code inside could possibly be causing my animation to complete immediately. And what I can do to avoid the problem.

Here's an example:

- (void)carouselCurrentItemIndexDidChange:(iCarousel *)carousel {
    [UIView
     animateWithDuration:5.0f
     delay:0
     options:
        UIViewAnimationOptionCurveEaseOut |
        UIViewAnimationOptionOverrideInheritedDuration |
        UIViewAnimationOptionOverrideInheritedCurve
     animations:^{
        myView.alpha = 0;
     }
     completion:^(BOOL finished){
         NSLog(@"Completed. Did it finish? %i", finished);
     }];
}

Last detail:
iCarousel's documentation mentions that you can change the useDisplayLink property of the carousel to avoid some conflicts with animation. This doesn't seem to make any difference.

Thanks in advance for help!


Solution

  • I found the problem deep within the source of iCarousel. For some reason within their library, they disable animations using [CATransaction setDisableActions:YES];, then reenable it later in a bunch of different places. One such places straddles a bunch of their callbacks which is preventing my animations from firing properly.

    Judging by the iCarousel code, this is very intentional, so I think I'll have to work around the issue in my own code.

    Edit: Here's my updated code that avoids this issue:

    - (void)carouselDidEndScrollingAnimation:(iCarousel *)carousel {
        BOOL previousDisableActions = [CATransaction disableActions];
        [CATransaction setDisableActions:NO];
    
        // Begin animation here.
    
        [CATransaction setDisableActions:previousDisableActions];
    }
    

    Update: The author of iCarousel has fixed this bug by internally adding the code I suggested above around each delegate call. Looks like this is fixed for good.