简体   繁体   English

iOS(Swift):使用for循环更改UILabel文本

[英]iOS (Swift): Changing UILabel text with a for loop

I have a for loop as follows: 我有一个for循环,如下所示:

@objc private func resetValue() {
    for i in stride(from: value, to: origValue, by: (value > origValue) ? -1 : 1) {
        value = i
    }
    value = origValue
}

And when value is set it updates a label : 当设置了value时,它将更新label

private var value = 1 {
    didSet {
        updateLabelText()
    }
}

private func updateLabelText() {

    guard let text = label.text else { return }

    if let oldValue = Int(text) { // is of type int?
        let options: UIViewAnimationOptions = (value > oldValue) ? .transitionFlipFromTop : .transitionFlipFromBottom
        UIView.transition(with: label, duration: 0.5, options: options, animations: { self.label.text = "\(value)" }, completion: nil)
    } else {
        label.text = "\(value)"
    }
}

I was hoping that if value=5 and origValue=2 , then the label would flip through the numbers 5,4,3,2 . 我希望如果value=5origValue=2 ,那么标签将翻转数字5,4,3,2 However, this is not happening - any suggestions why, please? 但是,这没有发生-请问为什么有任何建议?

I've tried using a delay function: 我试过使用延迟功能:

func delay(_ delay:Double, closure: @escaping ()->()) {
    DispatchQueue.main.asyncAfter(
        deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure)
}

and then placing the following within the stride code: 然后将以下内容放入stride代码中:

delay(2.0) { self.value = i }

However, this doesn't seem to work either. 但是,这似乎也不起作用。

Thanks for any help offered. 感谢您提供的任何帮助。

UIKit won't be able to update the label until your code is finished with the main thread, after the loop completes. 循环完成后,直到主线程完成代码后,UIKit才能更新标签。 Even if UIKit could update the label after each iteration of the loop, the loop is going to complete in a fraction of a second. 即使UIKit可以在循环的每次迭代后更新标签,循环也将在不到一秒钟的时间内完成。

The result is that you only see the final value. 结果是您只能看到最终值。

When you attempted to introduce the delay, you dispatched the update to the label asynchronously after 0.5 second; 当您尝试引入延迟时,您会在0.5秒后异步将更新分发到标签。 Because it is asynchronous, the loop doesn't wait for the 0.5 second before it continues with the next iteration. 因为它是异步的,所以循环在继续下一次迭代之前不会等待0.5秒。 This means that all of the delayed updates will execute after 0.5 seconds but immediately one after the other, not 0.5 seconds apart. 这意味着所有延迟的更新将在0.5秒后执行,但立即执行一次,而不是相隔0.5秒。 Again, the result is you only see the final value as the other values are set too briefly to be visible. 同样,结果是您只能看到最终值,因为其他值设置得太短而看不到。

You can achieve what you want using a Timer : 您可以使用Timer实现您想要的:

func count(fromValue: Int, toValue: Int) {
    let stride = fromValue > toValue ? -1 : 1
    self.value = fromValue
    let timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats:true) { [weak self] (timer) in
        guard let strongSelf = self else {
            return
        }
        strongSelf.value += stride
        if strongSelf.value == toValue {
            timer.invalidate()
        }
    }
}

I would also update the didSet to send the oldValue to your updateLabelText rather than having to try and parse the current text. 我还将更新didSet ,将oldValue发送到您的updateLabelText而不必尝试解析当前文本。

private var value = 1 {
    didSet {
        updateLabelText(oldValue: oldValue, value: value)
    }
}

private func updateLabelText(oldValue: Int, value: Int) {
    guard oldValue != value else {
        self.label.text = "\(value)"
        return
    }

    let options: UIViewAnimationOptions = (value > oldValue) ? .transitionFlipFromTop : .transitionFlipFromBottom
    UIView.transition(with: label, duration: 0.5, options: options, animations: { self.label.text = "\(value)" }, completion: nil)
}

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

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