如何为倒计时器

时间:2015-05-17 16:22:35

标签: ios swift animation timer sprite-kit

我正在尝试为我的应用添加倒计时,但我遇到了动画问题。我想要的外观类似于下面显示的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但是看不到一种为精灵的一部分着色的方法,似乎整个精灵都会被改变。

有没有人知道在这里是否可以选择着色,还是有办法减少图像地图集使用的内存?

由于

3 个答案:

答案 0 :(得分:18)

你可以使用CAShapeLayer并按照以下方式设置笔画结束的动画:

更新 Xcode 9•Swift 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的方法

start -ngle在-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中设置endTime并将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 = timeLeft
    // 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

答案 1 :(得分: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)))
        }
    }
}

答案 2 :(得分:0)

感谢@Leo Dabu的出色回答,我看到有人问为什么代码不起作用/无法在自己的项目上实现。使用CABasicAnimation时,请牢记以下提示:

  • 我们应该将动画添加到视图中已经存在的图层中,即确保在view.layer.addSublayer之后调用layer.add。
  • 请不要在viewDidLoad中制作动画,因为我们无法确定该图层是否已存在。

所以我们可以尝试类似的东西:

override func viewDidLoad() {
    super.viewDidLoad()
    drawBgShape()
    drawTimeLeftShape()
    ...
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    // move the setup of animation here
    strokeIt.fromValue = 0
    strokeIt.toValue = 1
    strokeIt.duration = timeLeft
    timeLeftShapeLayer.add(strokeIt, forKey: nil)
}

附有一些很好的参考资料,可以帮助我阐明这一点。希望这可以帮助并度过美好的一天;)

https://stackoverflow.com/a/13066094/11207700

https://stackoverflow.com/a/43006847/11207700