iOS (Swift):使用 for 循环更改 UILabel 文本
iOS (Swift): Changing UILabel text with a for loop
我有一个for循环如下:
@objc private func resetValue() {
for i in stride(from: value, to: origValue, by: (value > origValue) ? -1 : 1) {
value = i
}
value = origValue
}
并且当设置 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)"
}
}
我希望如果 value=5
和 origValue=2
,那么标签会翻转数字 5,4,3,2
。然而,这并没有发生——请问有什么建议吗?
我试过使用延迟函数:
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)
}
然后将以下内容放入 stride
代码中:
delay(2.0) { self.value = i }
然而,这似乎也不起作用。
感谢您提供的任何帮助。
UIKit 将无法更新标签,直到您的代码在主线程中完成,在循环完成之后。即使 UIKit 可以在每次循环迭代后更新标签,循环也会在几分之一秒内完成。
结果是您只能看到最终值。
当您尝试引入延迟时,您在 0.5 秒后将更新异步发送到标签;因为它是异步的,所以循环在继续下一次迭代之前不会等待 0.5 秒。这意味着所有延迟更新将在 0.5 秒后执行,但会一个接一个地执行,而不是相隔 0.5 秒。同样,结果是您只能看到最终值,因为其他值设置得太简单以至于看不到。
您可以使用 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()
}
}
}
我还会更新 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)
}
我有一个for循环如下:
@objc private func resetValue() {
for i in stride(from: value, to: origValue, by: (value > origValue) ? -1 : 1) {
value = i
}
value = origValue
}
并且当设置 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)"
}
}
我希望如果 value=5
和 origValue=2
,那么标签会翻转数字 5,4,3,2
。然而,这并没有发生——请问有什么建议吗?
我试过使用延迟函数:
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)
}
然后将以下内容放入 stride
代码中:
delay(2.0) { self.value = i }
然而,这似乎也不起作用。
感谢您提供的任何帮助。
UIKit 将无法更新标签,直到您的代码在主线程中完成,在循环完成之后。即使 UIKit 可以在每次循环迭代后更新标签,循环也会在几分之一秒内完成。
结果是您只能看到最终值。
当您尝试引入延迟时,您在 0.5 秒后将更新异步发送到标签;因为它是异步的,所以循环在继续下一次迭代之前不会等待 0.5 秒。这意味着所有延迟更新将在 0.5 秒后执行,但会一个接一个地执行,而不是相隔 0.5 秒。同样,结果是您只能看到最终值,因为其他值设置得太简单以至于看不到。
您可以使用 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()
}
}
}
我还会更新 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)
}