更新屏幕外的 UILabels 导致它们 "Snap" 返回
Updating UILabels Off-Screen Causing Them To "Snap" Back
背景信息
我正在构建一个微型秒表应用程序。它由一个带有显示时间标签的主视图和两个按钮组成:开始和停止。
开始按钮激活 NSTimers
,然后调用计算经过时间的方法,然后相应地更新标签。停止按钮只是使计时器无效。
在右上角,有一个箭头按钮,可以将所有 UI 元素向左移动并显示菜单。当计时器而不是 运行 并且标签没有被更新时,这很有效。
问题
但是,当 运行 计时器并因此同时更新标签时,在开始动画后不久,所有内容都会快速恢复到之前的位置。使用停止按钮使计时器无效时,动画再次正常工作。
演示
代码
动画 toggleMenu()
UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: .CurveEaseOut, animations: {
if self.arrow.frame.origin.x >= screenBounds.width/2 {
//if menu is NOT visible (mainView ON-SCREEN, menu right)
for element in self.UIElements {element.frame.origin.x -= screenBounds.width}
self.arrow.frame.origin.x = 0
self.arrow.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI))
} else {
//if menu IS visible (mainView left, menu ON-SCREEN)
for element in self.UIElements {element.frame.origin.x += screenBounds.width}
self.arrow.frame.origin.x = screenBounds.width-self.arrow.frame.width
self.arrow.transform = CGAffineTransformMakeRotation(CGFloat(0))
}
}, completion: nil)
正在调用定时器 updateTime()
更新标签
let currentTime = NSDate.timeIntervalSinceReferenceDate()
var elapsedTime: NSTimeInterval = currentTime - startTime
let hrs = UInt8(elapsedTime/3600)
elapsedTime -= NSTimeInterval(hrs)*3600
let mins = UInt8(elapsedTime/60)
elapsedTime -= NSTimeInterval(mins)*60
let secs = UInt8(elapsedTime)
elapsedTime -= NSTimeInterval(secs)
let strHrs = String(format: "%02d", hrs)
let strMins = String(format: "%02d", mins)
let strSecs = String(format: "%02d", secs)
//update time labels
self.time.text = "\(strHrs):\(strMins)"
self.secs.text = "\(strSecs)"
尝试次数
没有运气,我试过了...
- ...动画结束后隐藏标签
- ...在动画完成后动画化/隐藏所有元素的超级视图(
clipsToBounds
设置为真)
备注
我想...
- ...注释掉正在更新标签的行"fixes" 问题
- ...动画 UI 元素仅移动几个像素(如 100px)会导致同样的问题,这意味着该问题发生在屏幕上和屏幕外
有什么想法吗?
提前致谢!
当您更新标签时,Auto Layout 是 运行 并且将您的 UI 元素放回它们的约束规定的位置。您不应更改受 Auto Layout 控制的对象的框架,否则您会得到意想不到的结果。
不是更新 UI 元素的 origin.x
,而是创建 @IBOutlet
到水平放置它们的 NSLayoutContraints
,然后更新 constant
属性 的约束并在动画循环中调用 self.view.layoutIfNeeded()
。
让所有 UI 元素成为顶级 UIView 的子视图可能更容易,然后您只需要更新放置 UI 的一个约束=25=]水平查看以将其移出屏幕。
背景信息
我正在构建一个微型秒表应用程序。它由一个带有显示时间标签的主视图和两个按钮组成:开始和停止。
开始按钮激活 NSTimers
,然后调用计算经过时间的方法,然后相应地更新标签。停止按钮只是使计时器无效。
在右上角,有一个箭头按钮,可以将所有 UI 元素向左移动并显示菜单。当计时器而不是 运行 并且标签没有被更新时,这很有效。
问题
但是,当 运行 计时器并因此同时更新标签时,在开始动画后不久,所有内容都会快速恢复到之前的位置。使用停止按钮使计时器无效时,动画再次正常工作。
演示
代码
动画 toggleMenu()
UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: .CurveEaseOut, animations: {
if self.arrow.frame.origin.x >= screenBounds.width/2 {
//if menu is NOT visible (mainView ON-SCREEN, menu right)
for element in self.UIElements {element.frame.origin.x -= screenBounds.width}
self.arrow.frame.origin.x = 0
self.arrow.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI))
} else {
//if menu IS visible (mainView left, menu ON-SCREEN)
for element in self.UIElements {element.frame.origin.x += screenBounds.width}
self.arrow.frame.origin.x = screenBounds.width-self.arrow.frame.width
self.arrow.transform = CGAffineTransformMakeRotation(CGFloat(0))
}
}, completion: nil)
正在调用定时器 updateTime()
let currentTime = NSDate.timeIntervalSinceReferenceDate()
var elapsedTime: NSTimeInterval = currentTime - startTime
let hrs = UInt8(elapsedTime/3600)
elapsedTime -= NSTimeInterval(hrs)*3600
let mins = UInt8(elapsedTime/60)
elapsedTime -= NSTimeInterval(mins)*60
let secs = UInt8(elapsedTime)
elapsedTime -= NSTimeInterval(secs)
let strHrs = String(format: "%02d", hrs)
let strMins = String(format: "%02d", mins)
let strSecs = String(format: "%02d", secs)
//update time labels
self.time.text = "\(strHrs):\(strMins)"
self.secs.text = "\(strSecs)"
尝试次数
没有运气,我试过了...
- ...动画结束后隐藏标签
- ...在动画完成后动画化/隐藏所有元素的超级视图(
clipsToBounds
设置为真)
备注
我想...
- ...注释掉正在更新标签的行"fixes" 问题
- ...动画 UI 元素仅移动几个像素(如 100px)会导致同样的问题,这意味着该问题发生在屏幕上和屏幕外
有什么想法吗?
提前致谢!
当您更新标签时,Auto Layout 是 运行 并且将您的 UI 元素放回它们的约束规定的位置。您不应更改受 Auto Layout 控制的对象的框架,否则您会得到意想不到的结果。
不是更新 UI 元素的 origin.x
,而是创建 @IBOutlet
到水平放置它们的 NSLayoutContraints
,然后更新 constant
属性 的约束并在动画循环中调用 self.view.layoutIfNeeded()
。
让所有 UI 元素成为顶级 UIView 的子视图可能更容易,然后您只需要更新放置 UI 的一个约束=25=]水平查看以将其移出屏幕。