143 votes

La désactivation de l'implicite animations -[CALayer setNeedsDisplayInRect:]

J'ai une couche avec certains complexes, le code de dessin dans son drawInContext: la méthode. J'essaie de minimiser la quantité de dessin que j'ai besoin de le faire, donc je suis aide -setNeedsDisplayInRect: pour la mise à jour, le changement de pièces. Cela fonctionne magnifiquement. Toutefois, lorsque le système graphique des mises à jour de ma couche, c'est la transition de l'ancienne à la nouvelle image à l'aide d'un cross-fade. J'aimerais qu'il basculer instantanément.

J'ai essayé d'utiliser CATransaction pour désactiver les actions et définir la durée à zéro, et ne travaillent pas. Voici le code que j'utilise:

[CATransaction begin];
[CATransaction setDisableActions: YES];
[self setNeedsDisplayInRect: rect];
[CATransaction commit];

Est-il une autre méthode sur CATransaction je devrait utiliser à la place (j'ai aussi essayé -setValue:forKey: avec kCATransactionDisableActions, même résultat).

180voto

Brad Larson Points 122629

Vous pouvez le faire en définissant les actions dictionnaire sur la couche de revenir [NSNull null] comme une animation pour la clé appropriée. Par exemple, j'utilise

NSMutableDictionary *newActions = [[NSMutableDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"onOrderIn",
                                   [NSNull null], @"onOrderOut",
                                   [NSNull null], @"sublayers",
                                   [NSNull null], @"contents",
                                   [NSNull null], @"bounds",
                                   nil];
layer.actions = newActions;
[newActions release];

pour désactiver fade in / out animations à l'insertion ou à un changement de sous-couches à l'intérieur de l'un de mes couches, ainsi que des changements dans la taille et le contenu de la couche. Je crois que le contents - clé est celui que vous cherchez, afin de prévenir le fondu enchaîné sur la mise à jour du dessin.

90voto

mxcl Points 5921

Aussi:

[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];

//foo

[CATransaction commit];

32voto

user3378170 Points 1

Lorsque vous modifiez la propriété d'une couche, CA crée habituellement une transaction implicite de l'objet à animer le changement. Si vous ne voulez pas pour animer le changement, vous pouvez désactiver implicite animations par la création d'une transaction explicite et l'établissement de ses kCATransactionDisableActions propriété à true.

[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
// change properties here without animation
[CATransaction commit];

23voto

sam.kozin Points 706

En plus de Brad Larson réponse: pour les couches (qui sont créés par vous), vous pouvez utiliser la délégation au lieu de modifier la couche d' actions dictionnaire. Cette approche est plus dynamique et peut être plus performant. Et il permet de désactiver toutes les implicites des animations sans avoir à énumérer tous les animables clés.

Malheureusement, il est impossible d'utiliser UIViews comme couche personnalisée délégués, parce que chaque UIView est déjà un délégué de son propre calque. Mais vous pouvez utiliser une simple classe helper comme ceci:

@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

D'utilisation (à l'intérieur de la vue):

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

Parfois, il est pratique d'avoir une vue d'contrôleur en tant que délégué pour de la vue personnalisée sous-couches; dans ce cas, il n'est pas nécessaire pour une classe d'assistance, vous pouvez mettre en oeuvre actionForLayer:forKey: droit de la méthode à l'intérieur du contrôleur.

Mais, s'il vous plaît, n'essayez pas de modifier le délégué de l' UIViews'couche sous-jacente (par exemple, pour activer implicite animations) - les mauvaises choses qui se passera :)

Remarque: si vous souhaitez animer (pas de désactiver l'animation pour les) couche redessine, il est inutile de mettre des [CALayer setNeedsDisplayInRect:] appel à l'intérieur d'un CATransaction,, car la redéfinition peut (et probablement) se produit parfois plus tard. La bonne approche consiste à utiliser les propriétés personnalisées, comme décrit dans cette réponse.

8voto

Simon Points 297

En fait, je n'ai pas trouvé de réponses à la droite. La méthode qui permet de résoudre le problème pour moi c'était ça:

- (id<CAAction>)actionForKey:(NSString *)event {   
    return nil;   
}

Vous pouvez alors quelle que soit la logique, pour désactiver une animation spécifique, mais depuis que j'ai voulu supprimé tous, je suis retourné à néant.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X