Além da resposta de Brad Larson : para camadas personalizadas (criadas por você), você pode usar a delegação em vez de modificar o actions
dicionário da camada . Essa abordagem é mais dinâmica e pode ter melhor desempenho. E permite desabilitar todas as animações implícitas sem precisar listar todas as chaves animáveis.
Infelizmente, é impossível usar UIView
s como delegados de camadas personalizadas, porque cada UIView
um já é um delegado de sua própria camada. Mas você pode usar uma classe auxiliar simples como esta:
@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
Uso (dentro da 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
Às vezes, é conveniente ter o controlador do view como um representante das subcamadas personalizadas do view; Nesse caso, não há necessidade de uma classe auxiliar, você pode implementar o actionForLayer:forKey:
método dentro do controlador.
Nota importante: não tente modificar o delegado da UIView
camada subjacente (por exemplo, para ativar animações implícitas) - coisas ruins acontecerão :)
Nota: se você deseja animar (e não desativar a animação para) redesenhos de camadas, é inútil colocar uma [CALayer setNeedsDisplayInRect:]
chamada dentro de a CATransaction
, porque o redesenho real pode (e provavelmente ocorrerá) algumas vezes mais tarde. A boa abordagem é usar propriedades personalizadas, conforme descrito nesta resposta .
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ });