2016-07-19 46 views
0

ich eine Schicht soll so verhalten:CABasicAnimation läuft nach Implizite Animation,

correct

Stattdessen verhält es sich wie folgt aus:

improper

Die Karte Flip-Animation von zwei erstellt wird CABasicAnimation s in einem CAAnimationGroup angewendet. Der falsche Spin-Effekt tritt auf, weil die implizite Animation aus der Eigenschaftsänderung CALayer zuerst ausgeführt wird und dann meine in CABasicAnimation angegebene Animation ausgeführt wird. Wie kann ich die Ausführung der impliziten Animation stoppen, sodass nur meine angegebene Animation ausgeführt wird?

Hier ist der entsprechende Code:

class ViewController: UIViewController { 

    var simpleLayer = CALayer() 

    override func viewDidLoad() { 
    super.viewDidLoad() 

    let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap)) 
    self.view.addGestureRecognizer(tap) 

    simpleLayer.frame = CGRect(origin: CGPoint(x: view.bounds.width/2 - 50, y: view.bounds.height/2 - 50), size: CGSize(width: 100, height: 100)) 
    simpleLayer.backgroundColor = UIColor.blackColor().CGColor 
    view.layer.addSublayer(simpleLayer) 
    } 

    func handleTap() { 
    let xRotation = CABasicAnimation(keyPath: "transform.rotation.x") 
    xRotation.toValue = 0 
    xRotation.byValue = M_PI 

    let yRotation = CABasicAnimation(keyPath: "transform.rotation.y") 
    yRotation.toValue = 0 
    yRotation.byValue = M_PI 

    simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.y") 
    simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.x") 

    let group = CAAnimationGroup() 
    group.animations = [xRotation, yRotation] 
    group.duration = 0.6 
    group.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) 
    simpleLayer.addAnimation(group, forKey: nil) 
    } 
} 
+0

Ich bin eigentlich nicht positiv, wenn 'setValue (_: forKeyPath:)' wird von Core Animation überwacht, um implizite Animationen zu aktivieren oder nicht. Wenn Sie diese beiden Funktionsaufrufe mit einer ['CATtransaction' umgeben, die Aktionen deaktiviert] (http://calayer.com/core-animation/2016/05/17/catransaction-in-depth.html#preventing-animations-from- auftritt), behebt das das Problem? – LucasTizma

+0

Danke, @ LucasTizma! Das war der richtige Code. Ich habe es in einer Antwort unten ausführlich beschrieben. –

+1

Ich habe einen Downvote für die ursprüngliche Frage erhalten, jetzt ist der Wert "-1". Ich bin mir nicht sicher, warum ich den Downvote erhalten habe. Wenn der Downvoter einen Kommentar abgeben könnte, würde ich mich gerne mit seinem Anliegen befassen. Dies ist nicht so genau ein Anwendungsfall, wie es scheint. Diese Frage ist generisch anwendbar. Wenn Sie den Code zum Deaktivieren der impliziten Animation nicht hinzufügen, verhält sich die CAAnimationGroup nicht wie erwartet. –

Antwort

1

@LucasTizma hatte die richtige Antwort.

Umgeben Sie Ihre Animation mit CATransaction.begin(); CATransaction.setDisableActions(true) und CATransaction.commit(). Dies wird disable the implicit animation und die CAAnimationGroup animieren korrekt.

Hier ist das Endergebnis:

triangle flip animation

Dies ist der wichtige Code-Snippet in Swift 3:

CATransaction.begin() 
CATransaction.setDisableActions(true) 

let xRotation = CABasicAnimation(keyPath: "transform.rotation.x") 
xRotation.toValue = 0 
xRotation.byValue = M_PI 

let yRotation = CABasicAnimation(keyPath: "transform.rotation.y") 
yRotation.toValue = 0 
yRotation.byValue = M_PI 

simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.x") 
simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.y") 

let group = CAAnimationGroup() 
group.animations = [xRotation, yRotation] 
simpleLayer.add(group, forKey: nil) 

CATransaction.commit() 

Und das ist der vollständige Code für die dargestellte Animation mit einem iOS-App :

class ViewController: UIViewController { 

    var simpleLayer = CALayer() 

    override func viewDidLoad() { 
    super.viewDidLoad() 

    let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap)) 
    self.view.addGestureRecognizer(tap) 

    let ratio: CGFloat = 1/5 
    let viewWidth = view.bounds.width 
    let viewHeight = view.bounds.height 
    let layerWidth = viewWidth * ratio 
    let layerHeight = viewHeight * ratio 

    let rect = CGRect(origin: CGPoint(x: viewWidth/2 - layerWidth/2, 
             y: viewHeight/2 - layerHeight/2), 
         size: CGSize(width: layerWidth, height: layerHeight)) 

    let topRightPoint = CGPoint(x: rect.width, y: 0) 
    let bottomRightPoint = CGPoint(x: rect.width, y: rect.height) 
    let topLeftPoint = CGPoint(x: 0, y: 0) 

    let linePath = UIBezierPath() 

    linePath.move(to: topLeftPoint) 
    linePath.addLine(to: topRightPoint) 
    linePath.addLine(to: bottomRightPoint) 
    linePath.addLine(to: topLeftPoint) 

    let maskLayer = CAShapeLayer() 
    maskLayer.path = linePath.cgPath 

    simpleLayer.frame = rect 
    simpleLayer.backgroundColor = UIColor.black.cgColor 
    simpleLayer.mask = maskLayer 

    // Smooth antialiasing 
    // * Convert the layer to a simple bitmap that's stored in memory 
    // * Saves CPU cycles during complex animations 
    // * Rasterization is set to happen during the animation and is disabled afterwards 
    simpleLayer.rasterizationScale = UIScreen.main.scale 

    view.layer.addSublayer(simpleLayer) 
    } 

    func handleTap() { 
    CATransaction.begin() 
    CATransaction.setDisableActions(true) 
    CATransaction.setCompletionBlock({ 
     self.simpleLayer.shouldRasterize = false 
    }) 

    simpleLayer.shouldRasterize = true 

    let xRotation = CABasicAnimation(keyPath: "transform.rotation.x") 
    xRotation.toValue = 0 
    xRotation.byValue = M_PI 

    let yRotation = CABasicAnimation(keyPath: "transform.rotation.y") 
    yRotation.toValue = 0 
    yRotation.byValue = M_PI 

    simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.x") 
    simpleLayer.setValue(M_PI, forKeyPath: "transform.rotation.y") 

    let group = CAAnimationGroup() 
    group.animations = [xRotation, yRotation] 
    group.duration = 1.2 
    group.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) 
    simpleLayer.add(group, forKey: nil) 

    CATransaction.commit() 
    } 
} 
+0

Gut zu hören, dass es funktioniert hat! Als Randnotiz sollten Sie in der Lage sein, diese Alias-Kanten zu korrigieren, indem Sie die Ebene während der Animation rastern (und die Rasterisierungsskala auf die Skalierung des Hauptbildschirms einstellen). – LucasTizma

+0

Danke @LucasTizma. Das hat auch gut funktioniert! Ich fügte der Antwort den Code für glattes Antialiasing hinzu. –

+0

Im Idealfall werden Sie während der Animation nur gerastert und danach deaktiviert. Sie können Transaktionen noch einmal verwenden [um zu wissen, wann Ihre Animationen fertig sind] (http://calayer.com/core-animation/2016/05/17/catransaction-in-depth.html#getting-notified-with-animations -finish), damit Sie die Rasterung deaktivieren können. – LucasTizma

-1

Sie sind 2 separate Animationen erstellen und sie in einer Animationsgruppe anwenden. Wenn Sie das tun, werden sie in 2 diskreten Schritten angewendet.

Es sieht so aus, als ob Sie nicht wollen. Wenn nicht, dann erstellen Sie nicht zwei separate Animationen, eine auf transform.rotation.x und die andere auf transform.rotation.y. Verknüpfen Sie stattdessen beide Änderungen mit einer Transformationsmatrix und wenden Sie die geänderte Transformationsmatrix als einzelne Animation an.

+0

Mit Ihrem Feedback habe ich diesen Code versucht, aber es ist immer noch nicht richtig: https://gist.github.com/benmorrow/174e4f16053ac979ed62cee0d82c9560 –

+0

Versuchen Sie zuerst eine PI-Rotation um x, dann eine PI-Rotation um y, um die Transformation anwenden. Das ist nicht dasselbe wie eine PI Rotation entlang der 1,1,0 bis 0,0,0 Linie. –

+0

Ja, Sie hatten Recht. Dieser Effekt ist fast da. Ich habe den Gist aus dem vorherigen Kommentar aktualisiert, wenn Sie den neuen Code sehen möchten.Der Effekt, nach dem ich suche, ist jedoch immer noch nicht da, weil die Animation, die er erzeugt, einer Rotation um die z-Achse entspricht. Hier ist ein Gif davon: http://i.imgur.com/FpQMOHy.gifv Ich bin auf der Suche nach der Vorderseite Gesicht zu Flip wie in der ersten GIF in der Hauptfrage –