How to disable CALayer implicit animations?

It's driving me crazy! I am working on a drawing application. Let's say I am working on a UIView called sheet.

I am adding some sublayers to this view ([sheet.layer addSublayer:...]) and then I want to draw into them. To do so I am creating a CGImageRef and putting it into the layer's contents. But it's animated and I don't want that.

I tried everything:

  • removeAnimationForKey:
  • removeAllAnimations
  • set the actions dictionary
  • using the actionlayer delegate
  • [CATransaction setDisableAnimations:YES]

It's seems correct. I don't understand why this layer is still animated ;_;
Am I doing something wrong? Is there a secret way?


Solution 1:

Swift

CATransaction.begin()
CATransaction.setDisableActions(true)

// change layer properties that you don't want to animate

CATransaction.commit()

Solution 2:

You have to explicitly disable animations by wrapping your code in a CATransaction

[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue
                 forKey:kCATransactionDisableActions];
layer.content = someImageRef;
[CATransaction commit];

Solution 3:

As of Mac OS X 10.6 and iOS 3, CATransaction also has a setDisableActions method that sets the value for key kCATransactionDisableActions.

[CATransaction begin];
[CATransaction setDisableActions:YES];

layer.content = someImageRef;

[CATransaction commit];

In Swift, I like to use this extension method:

extension CATransaction {
    class func withDisabledActions<T>(_ body: () throws -> T) rethrows -> T {
        CATransaction.begin()
        CATransaction.setDisableActions(true)
        defer {
            CATransaction.commit()
        }
        return try body()
    }
}

You can then use it like this:

CATransaction.withDisabledActions {
    // your stuff here
}

Solution 4:

Another way:

  1. You should disable default animation of your sheet.layer, which is called implicitly when adding sublayer.

  2. You should also content-animation of each sublayer. Of course, you can use "kCATransactionDisableActions" of CATransaction each time you set sublayer.content. But, you can disable this animation once, when you are creating your sublayer.


Here is code:

// disable animation of container
sheet.layer.actions = [NSDictionary dictionaryWithObject:[NSNull null] 
                                                  forKey:@"sublayers"];

// disable animation of each sublayer
sublayer.layer.actions = [NSDictionary dictionaryWithObject:[NSNull null] 
                                                     forKey:@"content"];

// maybe, you'll also have to disable "onOrderIn"-action of each sublayer.       

Solution 5:

Swift 4 extension :

extension CATransaction {

    static func disableAnimations(_ completion: () -> Void) {
        CATransaction.begin()
        CATransaction.setDisableActions(true)
        completion()
        CATransaction.commit()
    }

}

Usage :

    CATransaction.disableAnimations {
        // things you don't want to animate
    }