在iOS应用中使用计时器和循环平滑动画

时间:2017-04-19 04:39:43

标签: swift animation timer grand-central-dispatch

我的ViewController的星级评分如此(除了有10颗星)

enter image description here

当用户为某些没有评级的对象打开ViewController时,我想用非常简单的方式指出用户对这些星星的关注:动画明星突出显示(你可以在每个字母的现实世界中看到这样的行为)一个接一个地突出显示)。

  1. 一颗星突出显示
  2. 两颗星突出显示
  3. 三颗星突出显示
  4. ......
  5. 关闭所有这些
  6. 所以这就是我这样做的方式

    func delayWithSeconds(_ seconds: Double, completion: @escaping () -> ()) {
        DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
            completion()
        }
    } 
    
    func ratingStarsAnimation() {
        for i in 1...11 {
            var timer : Double = 0.6 + Double(i)*0.12
            delayWithSeconds(timer) {
                ratingStars.rating = (i < 10) ? Double(i) : 0
            }
        }
    }
    

    这里发生了什么?我有一个名为delayWithSeconds的函数来延迟动作,我使用这个函数来延迟每个星形突出显示。 0.6是动画开始前的初始延迟。在所有星星突出显示后 - 最后一步是关闭所有星星的突出显示。 这段代码有效,但我不能说它很顺利。

    我的问题是:

    1. 如何更改0.6 + Double(i)* 0.12以获得流畅的动画效果?
    2. 我认为我的延迟解决方案并不好 - 如何更好地解决平滑明星突出任务?

1 个答案:

答案 0 :(得分:2)

查看CADisplaylink类。它是一个专门的计时器,链接到屏幕的刷新率,在iOS上这是60fps。 它是许多第三方动画库的支柱。

用法示例:

var displayLink: CADisplayLink?
let start: Double = 0
let end: Double = 10
let duration: CFTimeInterval = 5 // seconds
var startTime: CFTimeInterval = 0

let ratingStars = RatingView()

func create() {
    displayLink = CADisplayLink(target: self, selector: #selector(tick))
    displayLink?.add(to: .main, forMode: .defaultRunLoopMode)
}

func tick() {
    guard let link = displayLink else {
        cleanup()
        return
    }

    if startTime == 0 { // first tick
        startTime = link.timestamp
        return
    }

    let maxTime = startTime + duration
    let currentTime = link.timestamp

    guard currentTime < maxTime else {
        finish()
        return
    }

    // Add math here to ease the animation

    let progress = (currentTime - startTime) / duration
    let progressInterval = (end - start) * Double(progress)

    // get value =~ 0...10
    let normalizedProgress = start + progressInterval


    ratingStars.rating = normalizedProgress
}

func finish() {
    ratingStars.rating = 0
    cleanup()
}

func cleanup() {
    displayLink?.remove(from: .main, forMode: .defaultRunLoopMode)
    displayLink = nil
    startTime = 0
}

首先,这将使您的动画更加流畅。如果你想添加缓动,你仍然需要添加一些三角函数,但这不应该太困难。