In addition to Brad Larson's answer: for custom layers (that are created by you) you can use delegation instead of modifying layer's actions
dictionary. This approach is more dynamic and may be more performant. And it allows disabling all implicit animations without having to list all animatable keys.
Unfortunately, it's impossible to use UIView
s as custom layer delegates, because each UIView
is already a delegate of its own layer. But you can use a simple helper class like this:
@interface MyLayerDelegate : NSObject
@property (nonatomic, assign) BOOL disableImplicitAnimations;
@end
@implementation MyLayerDelegate
- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
{
if (self.disableImplicitAnimations)
return (id)[NSNull null]; // disable all implicit animations
else return nil; // allow implicit animations
// you can also test specific key names; for example, to disable bounds animation:
// if ([event isEqualToString:@"bounds"]) return (id)[NSNull null];
}
@end
Usage (inside the view):
MyLayerDelegate *delegate = [[MyLayerDelegate alloc] init];
// assign to a strong property, because CALayer's "delegate" property is weak
self.myLayerDelegate = delegate;
self.myLayer = [CALayer layer];
self.myLayer.delegate = delegate;
// ...
self.myLayerDelegate.disableImplicitAnimations = YES;
self.myLayer.position = (CGPoint){.x = 10, .y = 42}; // will not animate
// ...
self.myLayerDelegate.disableImplicitAnimations = NO;
self.myLayer.position = (CGPoint){.x = 0, .y = 0}; // will animate
Sometimes it's convenient to have view's controller as a delegate for view's custom sublayers; in this case there is no need for a helper class, you can implement actionForLayer:forKey:
method right inside the controller.
Important note: don't try to modify the delegate of UIView
's underlying layer (e.g. to enable implicit animations) — bad things will happen :)
Note: if you want to animate (not disable animation for) layer redraws, it is useless to put [CALayer setNeedsDisplayInRect:]
call inside a CATransaction
, because actual redrawing may (and probably will) happen sometimes later. The good approach is to use custom properties, as described in this answer.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ });
– Muriate