2016-03-29 66 views
1

我正試圖在屏幕上每秒創建一個新的動畫線。每一秒我都會得到一條新線,但它會覆蓋舊線。我不知道爲什麼,但這可能是我忽略的一些愚蠢的東西。這裏是我的代碼:For Loop Overriding Animations

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) 
     } 
    } 
} 

感謝您的幫助

編輯1:

以下是我正在與動畫時間有一個問題,基本上動畫互相覆蓋:

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) 
} 
+1

這段代碼中的「self」是什麼?如果你想要出現多條線,你將不得不製作多個這樣的對象。 –

+0

@KurtRevis我的意思是,有沒有更簡單的方法來做這樣的事情? –

+0

@KurtRevis自己也是一個'線'類,它有'CAShapeLayer'的超類 –

回答

1

每次你做一個動畫時,你的代碼將取代CAShapeLayer的路徑,所以對於你製作的每一個「行」,你都會丟失過去的行。

要顯示多行,你既可以:

  1. 添加多個子路徑的CAShapeLayer的路徑,每行一個,使用方法UIBezierPath.appendPath
  2. 使用多個CAShapeLayer s,每行一個。

以下是替代#1,它與您當前的代碼相比變化較小。這是一個自包含的示例,您可以將其添加到名爲ViewController的視圖控制器中的新iOS項目中。

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() 
     } 
    } 
} 

而結果:

Animated GIF of the resulting animation

這裏有一種方法做替代2#。我使animationTime時間更長,以便您可以看到每行的動畫可以重疊。

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

好吧,工作謝謝:)。然而,當我在第一個結束之前開始一個新行時,它會迫使仍在進行動畫製作的行結束。有沒有解決的辦法?再次感謝。 –

+0

如果您需要這樣做,那麼爲每一行使用一個單獨的'CAShapeLayer'會更容易。那麼每一行只需要一個動畫,而且它們都是獨立的,所以如果它們中的一些在同一時間進行動畫製作並不重要。你沒有顯示設置'CAShapeLayer'的代碼,所以我沒有試圖做到這一點。 –

+0

添加代碼爲每一行創建一個獨立的圖層。 –