2015-05-17 95 views
1

我想向我的应用程序添加一个倒计时,并且在动画时遇到问题。我所看到的外观与下面显示的iPad倒计时类似,红色条随着时钟倒数而增加。 enter image description here如何为倒数计时器创建一个循环进度指示器

起初,我创建了一个影像地图集以倒计时的每半秒钟一个单独的图像但这似乎需要大量的内存来运行,因此崩溃的应用程序,所以我现在必须找到一种替代方法。

我一直在寻找着色这里https://developer.apple.com/library/prerelease/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Sprites/Sprites.html#//apple_ref/doc/uid/TP40013043-CH9,但看不到一种颜色的部分精灵的方式,似乎整个精灵会改变。

有没有人知道在这里着色会是一个选择,还是有减少图像地图集使用的内存的方法?

感谢

+1

是否有你需要SpriteKit这样做的一个原因?通常,您可以通过在CAShapeLayer中将UIBezierPath的strokeEnd属性动画化来实现此目的。 – rdelmar

+0

SpriteKit除此之外没有任何理由用于游戏的其余部分,并开始寻找能否让计时器工作。还没有使用贝塞尔路径,但会考虑到这一点。谢谢你的帮助。 – user1759949

回答

12

则可以使用CAShapeLayer和动画行程结束如下操作:

更新的Xcode 9•斯威夫特4

定义时间留给

let timeLeftShapeLayer = CAShapeLayer() 
let bgShapeLayer = CAShapeLayer() 
var timeLeft: TimeInterval = 60 
var endTime: Date? 
var timeLabel = UILabel() 
var timer = Timer() 
// here you create your basic animation object to animate the strokeEnd 
let strokeIt = CABasicAnimation(keyPath: "strokeEnd") 

定义一种方法来创建de UIBezierPath

由startAngle在-90˚和endAngle 270

func drawBgShape() { 
    bgShapeLayer.path = UIBezierPath(arcCenter: CGPoint(x: view.frame.midX , y: view.frame.midY), radius: 
     100, startAngle: -90.degreesToRadians, endAngle: 270.degreesToRadians, clockwise: true).cgPath 
    bgShapeLayer.strokeColor = UIColor.white.cgColor 
    bgShapeLayer.fillColor = UIColor.clear.cgColor 
    bgShapeLayer.lineWidth = 15 
    view.layer.addSublayer(bgShapeLayer) 
} 
func drawTimeLeftShape() { 
    timeLeftShapeLayer.path = UIBezierPath(arcCenter: CGPoint(x: view.frame.midX , y: view.frame.midY), radius: 
     100, startAngle: -90.degreesToRadians, endAngle: 270.degreesToRadians, clockwise: true).cgPath 
    timeLeftShapeLayer.strokeColor = UIColor.red.cgColor 
    timeLeftShapeLayer.fillColor = UIColor.clear.cgColor 
    timeLeftShapeLayer.lineWidth = 15 
    view.layer.addSublayer(timeLeftShapeLayer) 
} 

添加标签

func addTimeLabel() { 
    timeLabel = UILabel(frame: CGRect(x: view.frame.midX-50 ,y: view.frame.midY-25, width: 100, height: 50)) 
    timeLabel.textAlignment = .center 
    timeLabel.text = timeLeft.time 
    view.addSubview(timeLabel) 
} 

在viewDidLoad中设定的结束时间和你CAShapeLayer添加到您的视图:

override func viewDidLoad() { 
    super.viewDidLoad() 
    view.backgroundColor = UIColor(white: 0.94, alpha: 1.0) 
    drawBgShape() 
    drawTimeLeftShape() 
    addTimeLabel() 
    // here you define the fromValue, toValue and duration of your animation 
    strokeIt.fromValue = 0 
    strokeIt.toValue = 1 
    strokeIt.duration = 60 
    // add the animation to your timeLeftShapeLayer 
    timeLeftShapeLayer.add(strokeIt, forKey: nil) 
    // define the future end time by adding the timeLeft to now Date() 
    endTime = Date().addingTimeInterval(timeLeft) 
    timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true) 
} 
更新时

时间

@objc func updateTime() { 
    if timeLeft > 0 { 
     timeLeft = endTime?.timeIntervalSinceNow ?? 0 
     timeLabel.text = timeLeft.time 
    } else { 
     timeLabel.text = "00:00" 
     timer.invalidate() 
    } 
} 

您可以使用此扩展度转换为弧度和显示时间

extension TimeInterval { 
    var time: String { 
     return String(format:"%02d:%02d", Int(self/60), Int(ceil(truncatingRemainder(dividingBy: 60)))) 
    } 
} 
extension Int { 
    var degreesToRadians : CGFloat { 
     return CGFloat(self) * .pi/180 
    } 
} 

Sample project

+0

感谢您的帮助。 – user1759949

+0

再次感谢,这完美的作品。你知道如何确保形状图层保留在后面,以便拖动它的任何精灵节点都会显示在最上面?我试过设置zposition,但是这在shapelayer和节点之间似乎不起作用。 – user1759949

+0

我会尝试使用SK来做它,并会让你知道 –

0

大的代码并回答!只是想我会建议以下。我将时间显示为1:00然后0:60,我认为这可能是由于代码的“ceil”部分。

我把它改成下面的样子(同样希望小于60的时候显示不同),它似乎已经消除了时间的重叠。

对于它的价值......

extension NSTimeInterval { 
    var time:String { 
     if self < 60 { 
      return String(format: "%02d", Int(floor(self%60))) 
     } else 
     { 
      return String(format: "%01d:%02d", Int(self/60), Int(floor(self%60))) 
     } 
    } 
}