简体   繁体   English

UIView.animate 似乎冻结了其他视图更新

[英]UIView.animate seems to freeze other view updates

I have a UIView that is a countdown clock, which I animate with UIView.animate.我有一个 UIView,它是一个倒计时时钟,我使用 UIView.animate 对其进行动画处理。 There is also a running timer that shows the time on a UILabel, when the timer is fired.还有一个正在运行的计时器,当计时器被触发时,它会在 UILabel 上显示时间。 When the game is in transition (during the count down), the UILabel stops changing.当游戏处于过渡状态时(倒计时期间),UILabel 停止变化。 I've put a "print" statement into the timer function and it shows up as expected.我在计时器 function 中添加了一个“打印”语句,它按预期显示。

I've been searching for hints about maybe the UIVIew.animate freezes other views, but I see multiple apps moving views at the same time.我一直在寻找有关 UIVIew.animate 冻结其他视图的提示,但我看到多个应用程序同时移动视图。 Maybe I'm supposed to put things on different thread?也许我应该把东西放在不同的线程上?

@objc func timerUpdate () {
        if gameIsRunning {
            let endTime = Date.init()
            let difference = endTime.timeIntervalSince(gameClock)
            let formattedString = String(format: "%3.1f",kDefaultGameClock - difference)
            timerLabel.text = "\(formattedString)"
        }
}


private func countDownFrom (x: Int) {
    if x != 0 && x > 0 {
        UIView.animate(withDuration: 1.0,
                       delay: 0.0,
                       usingSpringWithDamping: 0.5,
                       initialSpringVelocity:1.0,
                       options: .curveEaseOut,
                       animations: {
                        self.successLabel.text = "\(x)"
                        self.successLabel.transform = self.successLabel.transform.scaledBy(x: 4.0, y: 4.0)

        }, completion: {_ in
            self.successLabel.transform = self.successLabel.transform.scaledBy(x: 0.250, y: 0.250)
            if (x - 1 > 0) {
                self.countDownFrom(x: x - 1)
            } else {
                self.successLabel.text = kDefaultGoodGame
                self.successLabel.isHidden = true
                self.startTheGame()
                self.updateScreen()
            }
        })
    }
}

When I tried your code in an empty project, I was able to update both labels.当我在一个空项目中尝试您的代码时,我能够更新两个标签。

If timerLabel isn't being updated, it could be a thread issue.如果timerLabel未更新,则可能是线程问题。 UI updates should be on the main thread. UI 更新应该在主线程上。

DispatchQueue.main.async {
    self.timerLabel.text = "\(formattedString)"
}

For what it's worth, here is what I have working in an empty project.对于它的价值,这是我在一个空项目中所做的工作。

@IBOutlet weak var timerLabel: UILabel!
@IBOutlet weak var successLabel: UILabel!

let kDefaultGameClock = 30.0
var gameIsRunning = false
var gameClock = Date()

override func viewDidLoad() {
    super.viewDidLoad()
    start()
}

func start() {
    gameIsRunning = true
    countDownFrom(x: 30)
    Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(timerUpdate), userInfo: nil, repeats: true)
}

@objc func timerUpdate() {
    if gameIsRunning {
        let endTime = Date.init()
        let difference = endTime.timeIntervalSince(gameClock)
        let formattedString = String(format: "%3.1f", kDefaultGameClock - difference)
        timerLabel.text = "\(formattedString)" // Could be a main thread issue here?
    }
}

private func countDownFrom(x: Int) {
    if x != 0 && x > 0 {
        UIView.animate(withDuration: 1.0,
                       delay: 0.0,
                       usingSpringWithDamping: 0.5,
                       initialSpringVelocity:1.0,
                       options: .curveEaseOut,
                       animations: {
                        self.successLabel.text = "\(x)"
                        self.successLabel.transform = self.successLabel.transform.scaledBy(x: 4.0, y: 4.0)

        }, completion: {_ in
            self.successLabel.transform = self.successLabel.transform.scaledBy(x: 0.250, y: 0.250)
            if (x - 1 > 0) {
                self.countDownFrom(x: x - 1)
            } else {
                self.successLabel.text = ""
                self.successLabel.isHidden = true
                //self.startTheGame()
                //self.updateScreen()
            }
        })
    }
}

A little off topic, but you might want to declare your Timer as a variable to invalidate it once you're done updating the timerLabel.有点离题,但您可能希望将您的 Timer 声明为一个变量,以便在更新完 timerLabel 后使其无效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM