2017-02-10 9 views
5

Mam problem z zrozumieniem, dlaczego animacja nie działa zgodnie z oczekiwaniami. Co robie to:CAKeyFrameAnimation nie Liniowy dla wartości większych niż PI

  1. Tworzenie UIBezierPath z łuku przenieść etykiety wzdłuż tej drogi i animowanie udar ścieżkach.

    //Start Point is -.pi /2 to let the Arc start at the top. 
    //self.progress = Value between 0.0 and 1.0 
    let path : UIBezierPath = UIBezierPath.init(arcCenter: CGPoint.init(x: self.bounds.width * 0.5, y: self.bounds.height * 0.5), 
    radius: self.bounds.width * 0.5, startAngle: -.pi/2, endAngle: (2 * self.progress * .pi) - (.pi/2), clockwise: true) 
    return path 
    
  2. Dodaj tę ścieżkę do CAShapeLayer

    circlePathLayer.frame = bounds 
    circlePathLayer.path = self.path.cgPath 
    circlePathLayer.strokeStart = 0 
    circlePathLayer.strokeEnd = 1 
    
  3. Animowanie własności strokeEnd z CABasicAnimation

    let animation = CABasicAnimation(keyPath: "strokeEnd") 
    animation.repeatCount = HUGE 
    animation.fromValue = 0.0 
    animation.toValue = 1.0 
    animation.duration = self.animationDuration 
    animation.isRemovedOnCompletion = false 
    animation.fillMode = kCAFillModeBoth 
    
  4. Animowanie własności pozycja mojej wytwórni z CAKeyFrameAnimation

    let animationScore = CAKeyframeAnimation(keyPath: "position") 
    //some things I tried to fix 
    //animationScore.timingFunctions = [CAMediaTimingFunction(controlPoints: 0.250, 0.250, 0.750, 0.750)] 
    //animationScore.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionLinear) 
    animationScore.path = self.path.cgPath 
    animationScore.duration = self.animationDuration 
    animationScore.isRemovedOnCompletion = false 
    animationScore.fillMode = kCAFillModeBoth 
    animationScore.repeatCount = HUGE 
    
  5. Dodaj moje animacje do warstwy i oznakować

    self.circlePathLayer.add(animation, forKey: nil) 
    self.scoreLabel.layer.add(animationScore, forKey: nil) 
    

mój problem: Dla ProgressValues ​​większych niż 0,75 mojej wytwórni nie porusza się prędkością liniową. Wartości większe niż 0,75 oznaczają, że mój łuk jest większy niż PI. Dla wartości mniejszych niż 0,75 moja animacja działa bez zarzutu, a etykieta i obrys mają tę samą prędkość i znajdują się jeden na drugim.

GIF: Gif showing the animation

proszę ignorować 100% na etykiecie w tym gif moje postępy przy wartości 0,76.

Moja etykieta spowalnia po trzech czwartych mojego okręgu.

Mam nadzieję, że ktoś może mi pomóc. Wielkie dzięki

+0

Czy wyślesz wersję demo? Jeśli nie masz nic przeciwko? Sprawdzę to i wrócę do ciebie z rozwiązaniem –

+0

Nie widzę, żebyś ustawiał "calculode". Ale w każdym razie ... Dlaczego w ogóle korzystasz z animacji klatek kluczowych? Po prostu obróć etykietę wokół środka okręgu jako punktu zakotwiczenia, jak planeta. Pomyśl o zegarowej ręce (pamiętasz zegary z rękami?). Będziesz potrzebował drugiego obrotu wokół centrum etykiet, aby utrzymać go w pozycji pionowej. – matt

+0

Dziękuję wam za odpowiedzi. @matt ustawienie 'calculationMode' niczego nie zmieniło. Ale obracanie mojej etykiety wokół anchorPoint wydaje się warte wypróbowania. Jak to zrobić? Czy to po prostu "CABasicAnimation transform.rotation"? I musiałbym stworzyć "CAAnimationGroup", aby połączyć obie animacje, prawda? –

Odpowiedz

3

Animacja klatki kluczowej wprowadza niepotrzebne komplikacje. Wystarczy obrócić etykietę wokół centrum przy tej samej długości jak warstwa kształtu w skoku animacji:

enter image description here

(przepraszam, że moja animacja zaczyna się na dole, a nie do góry, ale nie patrzył na swoje pytanie, kiedy napisałem kod, a teraz jestem zbyt leniwy, aby to zmienić!)

Jak to zrobić? To trzy animacje, wszystkie o tym samym czasie trwania:

  • Warstwa kształtu na strokeEnd, jak animacji.

  • "Ramię" biegnące przez środek okręgu, z etykietą jako podwarstwa na jednym końcu (tak, że etykieta pojawia się w promieniu koła). Ramię wykonuje animację transformacji obrotowej.

  • Etykieta wykonuje animację przekształcenia obrotu w przeciwnym kierunku.Gdyby tak nie było, obróciłby się wraz z superlayerem. (Pomyśl o tym, jak działa diabelski młyn; fotela znajduje się na końcu ramienia, ale pozostaje w pozycji pionowej w stosunku do ziemi.)

To jest cały kod animacji:

let anim = CABasicAnimation(keyPath: "transform.rotation.z") 
    anim.fromValue = 0 
    anim.toValue = 5 
    anim.duration = 10 
    self.arm.layer.add(anim, forKey:nil) 

    let anim2 = CABasicAnimation(keyPath: "transform.rotation.z") 
    anim2.fromValue = 0 
    anim2.toValue = -5 
    anim2.duration = 10 
    self.lab.layer.add(anim2, forKey:nil) 

    let anim3 = CABasicAnimation(keyPath: "strokeEnd") 
    anim3.fromValue = 0 
    anim3.toValue = 1 
    anim3.duration = 10 
    self.shape.add(anim3, forKey:nil) 
+0

Przede wszystkim dziękuję za udzielenie tej pięknej odpowiedzi i wyjaśnienia. Uwielbiam analogię do diabelskiego koła. Tylko jedno pytanie: Rozumiem cel "ramienia", ale mam problem z ustaleniem, w jaki sposób mógłbym zrealizować coś takiego. Czy mógłbyś wyjaśnić trochę dalej? Oznaczenie jako zaakceptowanej odpowiedzi. –

+0

"Ramię" to tylko widok lub warstwa. Nie możesz go zobaczyć, ponieważ dałem mu jasne tło. Jego celem jest jedynie przesunięcie etykiety na orbitę wokół środka, pozwalając etykiecie na obracanie się w środku, aby pozostać w pozycji pionowej (jak diabelski młyn, jak już powiedziałem). Pomyśl o ramieniu jako "szprychy" koła. – matt

+0

Dobra, myślę, że mam pomysł. Jeszcze raz dziękuję za szybką odpowiedź. Bardzo mi pomogłeś! Btw: Czy masz pojęcie, dlaczego podążanie ścieżką z keyFrameAnimation nie działa zgodnie z zamierzeniami? –

Powiązane problemy