web-dev-qa-db-fra.com

Comment désactiver les animations implicites de CALayer?

Ça me rend fou! Je travaille sur une application de dessin. Disons que je travaille sur une feuille UIView appelée.

J'ajoute quelques sous-couches à cette vue ([sheet.layer addSublayer:...]), puis je souhaite y dessiner. Pour ce faire, je crée une variable CGImageRef et la place dans la variable contents de la couche. Mais c'est animé et je ne le veux pas.

J'ai tout essayé:

  • removeAnimationForKey:
  • removeAllAnimations
  • définir le dictionnaire d'actions
  • utilisation de la couche de couche delegate
  • [CATransaction setDisableAnimations:YES]

Cela semble correct. Je ne comprends pas pourquoi cette couche est toujours animée;
Est-ce que je fais quelque chose de mal? Y a-t-il un moyen secret?

36
Esepher

Vous devez désactiver explicitement les animations en encapsulant votre code dans une transaction CATransaction.

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

Rapide

CATransaction.begin()
CATransaction.setDisableActions(true)

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

CATransaction.commit()
25
Suragch

À partir de Mac OS X 10.6 et iOS 3, CATransaction dispose également d'une méthode setDisableActions qui définit la valeur de la clé kCATransactionDisableActions.

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

layer.content = someImageRef;

[CATransaction commit];

Dans Swift, j'aime utiliser cette méthode d'extension:

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

Vous pouvez ensuite l'utiliser comme ceci:

CATransaction.withDisabledActions {
    // your stuff here
}
15
zneak

Autrement:

  1. Vous devez désactiver l'animation par défaut de votre feuille.layer, qui est appelé implicitement lors de l'ajout d'une sous-couche.

  2. Vous devriez également contenu-animation de chaque sous-couche. Bien sûr, vous pouvez utiliser "kCATransactionDisableActions" de CATransaction chaque fois que vous définissez sublayer.content. Mais, vous pouvez désactiver cette animation une fois, lorsque vous créez votre sous-couche.


Voici le 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.       
11
holodnyalex

Code global réutilisable:

/**
 * Disable Implicit animation
 * EXAMPLE: disableAnim{view.layer?.position = 20}//Default animation is now disabled
 */
func disableAnim(_ closure:()->Void){
    CATransaction.begin()
    CATransaction.setDisableActions(true)
    closure()
    CATransaction.commit()
}

Ajoutez ce code n'importe où dans votre code (portée globale)

1
eonist

Extension Swift 4:

extension CATransaction {

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

}

Utilisation:

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

Swift 2

J'ai pu désactiver toutes les animations comme suit, où myView est la vue avec laquelle vous travaillez:

myView.layer.sublayers?.forEach { $0.removeAllAnimations() }

Et en guise de remarque, en supprimant toutes les couches:

myView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }
0
user4806509

avant en ajoutant le calque à votre vue avec [self.layer addSublayer:yourCALayer] et après son ajout, vous pouvez désactiver des propriétés animées spécifiques de votre CALayer en écrasant la clé d’animation. La clé que vous définissez sur NULL est nommée d'après la propriété, affichée ici comme si elle était exécutée pour la fonction layer.position = CGPoint(x,y);.

yourCALayer.actions = [NSDictionary dictionaryWithObject:[NSNull null] forKey:@"position"];

Comme la propriété actions est un NSDictionary qui n'autorise pas le stockage de nil, vous le définissez explicitement avec un objet NULL avec [NSNull null], identique à (id)kCFNull . Vous pouvez le faire pour tous les sous-calques en effectuant une itération dans tous les sous-calques couche vues avec ...

for (CALayer *iterationLayer in self.layer.sublayers ) {
    iterationLayer.actions = [NSDictionary dictionaryWithObject:[NSNull null] forKey:@"position"];
    //or for multiple keys at once
    NSNull *nop = [NSNull null];
    iterationLayer.actions = [NSDictionary dictionaryWithObjects:@[nop,nop] forKeys:@[@"position",@"contents"]];
}
0
Ol Sen

C'est une vieille question mais le problème demeure. Parfois, vous ne souhaitez pas que les animations que CALayer vous impose. Je n'étais pas satisfait de l'approche basée sur les transactions car je voulais simplement désactiver ces actions. Pour de bon. Voici une solution de Swift 4 à la sous-classe CALayer pour permettre le choix d’autoriser toute action ou de la désactiver globalement. Vous pouvez également créer des sous-classes CAShapeLayer, CATextLayer avec le même contenu:

public class ActionCALayer: CALayer {
    public var allowActions: Bool = false

    override public func action(forKey event: String) -> CAAction? {
        return allowActions ? super.action(forKey: event) : nil
    }
}
0
Ryan Francesconi