Oltre alla risposta di Brad Larson : per i livelli personalizzati (creati da te) puoi usare la delega invece di modificare il actions
dizionario dei livelli . Questo approccio è più dinamico e può essere più performante. E consente di disabilitare tutte le animazioni implicite senza dover elencare tutte le chiavi animabili.
Sfortunatamente, è impossibile usare UIView
s come delegati di layer personalizzati, perché ognuno UIView
è già un delegato del proprio layer. Ma puoi usare una semplice classe di supporto come questa:
@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
Utilizzo (all'interno della vista):
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
A volte è conveniente avere il controller di view come delegato per i sublayer personalizzati di view; in questo caso non è necessaria una classe helper, è possibile implementare il actionForLayer:forKey:
metodo direttamente all'interno del controller.
Nota importante: non tentare di modificare il delegato del UIView
livello sottostante (ad esempio per abilitare animazioni implicite) - accadranno cose brutte :)
Nota: se si desidera animare (non disabilitare l'animazione per) i ridisegni dei layer, è inutile inserire la [CALayer setNeedsDisplayInRect:]
chiamata all'interno di un CATransaction
, poiché il ridisegno effettivo può (e probabilmente accadrà) a volte più tardi. Il buon approccio è utilizzare proprietà personalizzate, come descritto in questa risposta .
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ });