我试图在屏幕上每秒创建一个新的动画线。每一秒我都会得到一条新线,但它会覆盖旧线。我不知道为什么,但它可能是我忽略的愚蠢行为。这是我的代码:
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)
}
答案 0 :(得分:1)
每次动画时,您的代码都会替换CAShapeLayer
的路径,因此对于您设置动画的每个“线”,都会丢失过去的行。
要显示多行,您可以:
UIBezierPath.appendPath
为CAShapeLayer
的路径添加多个子路径,每个路径一个。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()
}
}
}
结果:
这是一种替代#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()
}
}
}