2016-03-29 28 views
1

Ekranda her saniye yeni bir animasyonlu çizgi oluşturmaya çalışıyorum. Her saniyede yeni bir çizgi alıyorum, ancak eski olanı geçersiz kılıyor. Nedenini bilmiyorum ama muhtemelen aptal olduğum bir şey. animasyonlar birbirini geçersiz temelde ben animasyon zamanlama ile yaşıyorum bir sorun İşteDöngüleri Aşan Animasyonlar İçin

oluyor:

func repeatThis() { 
    var runningPath = UIBezierPath() 

    for x in 0...10 { 
     delay(Double(x)/10) { 
      let topLineStartPath = UIBezierPath(rect: CGRect(x: 0, y: x * 10, width: 1, height: 10)) 
      let topLineEndPath = UIBezierPath(rect: CGRect(x: 0, y: x * 10, width: Int(self.bounds.width), height: 10)) 

      let fullStartPath = runningPath.copy() as! UIBezierPath 
      fullStartPath.appendPath(topLineStartPath) 
      let fullEndPath = runningPath.copy() as! UIBezierPath 
      fullEndPath.appendPath(topLineEndPath) 

      let expAnimation: CABasicAnimation = CABasicAnimation(keyPath: "path") 
      expAnimation.fromValue = fullStartPath.CGPath 
      expAnimation.toValue = fullEndPath.CGPath 
      expAnimation.duration = self.animationTime 
      expAnimation.fillMode = kCAFillModeForwards 
      expAnimation.removedOnCompletion = false 
      self.addAnimation(expAnimation, forKey: nil) 
      print(x) 

      runningPath = fullEndPath 
     } 
    } 
} 

func delay(delay:Double, closure:()->()) { 
    dispatch_after(
     dispatch_time(
      DISPATCH_TIME_NOW, 
      Int64(delay * Double(NSEC_PER_SEC)) 
     ), 
     dispatch_get_main_queue(), closure) 
} 
yardım

func repeatThis() { 
    for x in 1...10 { 
     let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), Int64(x) * Int64(NSEC_PER_SEC)) 
     dispatch_after(time, dispatch_get_main_queue()) { 
      var topLinePatha: UIBezierPath { 
       return UIBezierPath(rect: CGRect(x: 0, y: 0 + (x * 10), width: 1, height: 10)) 
      } 

      var topLinePathb: UIBezierPath { 
       return UIBezierPath(rect: CGRect(x: 0, y: 0 + (x * 10), width: Int(UIScreen.mainScreen().bounds.width), height: 10)) 
      } 

      let expAnimation: CABasicAnimation = CABasicAnimation(keyPath: "path") 
      expAnimation.fromValue = topLinePatha.CGPath 
      expAnimation.toValue = topLinePathb.CGPath 
      expAnimation.duration = self.animationTime 
      expAnimation.fillMode = kCAFillModeForwards 
      expAnimation.removedOnCompletion = false 
      self.addAnimation(expAnimation, forKey: nil) 
      print(x) 
     } 
    } 
} 

Teşekkür

Düzenleme 1: İşte benim kod

+1

Bu kodda 'self' nedir? Birden fazla satırın görünmesini istiyorsanız, bu nesneden daha fazlasını yapmak zorunda kalacaksınız. –

+0

@KurtRevis Yani, böyle bir şey yapmanın daha kolay bir yolu var mı? –

+0

@KurtRevis de kendini 'CAShapeLayer' –

cevap

1

Her animasyon yaptığınızda, kodunuz CAShapeLayer'un yolunu değiştirir; böylece, uyguladığınız her "satır" için geçmiş satırları kaybedersiniz.

birden fazla satır göstermek için, ya da olabilir:

  1. yöntemi UIBezierPath.appendPath kullanarak, CAShapeLayer 'ın yolundan, her hat için bir çoklu alt yollarını ekleyin.
  2. Her satır için bir tane olmak üzere birden çok CAShapeLayer s kullanın.

Geçerli kodunuzdan daha küçük olan alternatif # 1. Bu, ViewController adlı bir görünüm denetleyicisinde yeni bir iOS projesine ekleyebileceğiniz bağımsız bir örnektir.

import UIKit 

class MyShapeLayer: CAShapeLayer { 
    var animationTime: NSTimeInterval = 0.75 

    func repeatThis() { 
     // Keep track of the path so far 
     var runningPath = UIBezierPath() 

     for x in 1...10 { 
      let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), Int64(x) * Int64(NSEC_PER_SEC)) 
      dispatch_after(time, dispatch_get_main_queue()) { 
       // We will add a rectangular subpath onto runningPath. 
       // It will be animated starting with: 
       let topLineStartPath = UIBezierPath(rect: CGRect(x: 0, y: x * 10, width: 1, height: 10)) 
       // and ending with: 
       let topLineEndPath = UIBezierPath(rect: CGRect(x: 0, y: x * 10, width: Int(self.bounds.width), height: 10)) 

       // Copy the running path, and add the starting and ending subpaths onto it 
       let fullStartPath = runningPath.copy() as! UIBezierPath 
       fullStartPath.appendPath(topLineStartPath) 
       let fullEndPath = runningPath.copy() as! UIBezierPath 
       fullEndPath.appendPath(topLineEndPath) 

       // Animate from fullStartPath to fullEndPath 
       let expAnimation: CABasicAnimation = CABasicAnimation(keyPath: "path") 
       expAnimation.fromValue = fullStartPath.CGPath 
       expAnimation.toValue = fullEndPath.CGPath 
       expAnimation.duration = self.animationTime 
       expAnimation.fillMode = kCAFillModeForwards 
       expAnimation.removedOnCompletion = false 
       self.addAnimation(expAnimation, forKey: nil) 
       print(x) 

       // The next time through the loop, add on to this iteration's ending path 
       runningPath = fullEndPath 
      } 
     } 
    } 
} 

class MyView: UIView { 
    override class func layerClass() -> AnyClass { 
     return MyShapeLayer.self 
    } 
} 

class ViewController: UIViewController { 
    override func loadView() { 
     self.view = MyView() 
     self.view.backgroundColor = UIColor.whiteColor() 
    } 

    override func viewDidLoad() { 
     if let myShapeLayer = self.view.layer as? MyShapeLayer { 
      myShapeLayer.repeatThis() 
     } 
    } 
} 

Ve sonuç: Burada

Animated GIF of the resulting animation

alternatif 2. yapmanın bir yolu. Animasyonu daha uzun süre yaptım, böylece her satırın animasyonlarının üst üste gelebileceğini görebiliyorsunuz.

class LineAtATimeView: UIView { 
    var animationTime = 1.25 // longer duration so line animations overlap 

    func repeatAddingLines() { 
     for x in 1...10 { 
      let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), Int64(x) * Int64(NSEC_PER_SEC)) 
      dispatch_after(time, dispatch_get_main_queue()) { 
       let newLayer = CAShapeLayer() 
       newLayer.frame = self.bounds 
       self.layer.addSublayer(newLayer) 

       let topLineStartPath = UIBezierPath(rect: CGRect(x: 0, y: x * 10, width: 1, height: 10)) 
       let topLineEndPath = UIBezierPath(rect: CGRect(x: 0, y: x * 10, width: Int(self.bounds.width), height: 10)) 

       let expAnimation: CABasicAnimation = CABasicAnimation(keyPath: "path") 
       expAnimation.fromValue = topLineStartPath.CGPath 
       expAnimation.toValue = topLineEndPath.CGPath 
       expAnimation.duration = self.animationTime 
       expAnimation.fillMode = kCAFillModeForwards 
       expAnimation.removedOnCompletion = false 
       newLayer.addAnimation(expAnimation, forKey: nil) 
      } 
     } 
    } 
} 

class ViewController2: UIViewController { 
    override func loadView() { 
     self.view = LineAtATimeView() 
     self.view.backgroundColor = UIColor.whiteColor() 
    } 

    override func viewDidLoad() { 
     if let v = self.view as? LineAtATimeView { 
      v.repeatAddingLines() 
     } 
    } 
} 
+0

Alright'un süper sınıfı olan bir 'Satır' dersi verdi, teşekkürler :). Bununla birlikte, birincisi bitmeden yeni bir satıra başladığımda, bitmek üzere hala hareketli olanı zorlar. Bunun etrafında bir yolu var mı? Tekrar teşekkürler. –

+0

Bunu yapmanız gerekiyorsa, her satır için ayrı bir "CAShapeLayer" kullanmak çok daha kolay olurdu. Sonra her satırın sadece tek bir animasyona ihtiyacı vardır ve hepsi bağımsızdır, bu yüzden bazılarının aynı anda animasyon yapması önemli değildir. CAShapeLayer'ı oluşturan kodu göstermediniz, ben de bunu yapmaya çalışmadım. –

+0

Her satır için bağımsız bir katman oluşturmak için kod eklendi. –

İlgili konular