为什么在主线程上调用闭包时我的动画会被忽略?
Why is my animation ignored when invoking a closure on the main thread?
要从主视图(子视图 "dims" 父视图,因此称为 dimView)中删除子视图,我使用动画;它基本上将子视图移向屏幕底部并最终移出屏幕:
let centerY = CGRectGetMidY(view.bounds)
let animation: CABasicAnimation = CABasicAnimation(keyPath: "position")
animation.removedOnCompletion = false
animation.fillMode = kCAFillModeForwards
animation.fromValue = NSValue(CGPoint: view.center)
animation.toValue = NSValue(CGPoint: CGPoint(x: view.center.x, y: 4 * centerY))
animation.duration = 0.2
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
dimView.layer.addAnimation(animation, forKey: "DimRemovingAnimation")
然后通过一个事件驱动函数,我这样调用这个动画:
@IBAction func done(sender: AnyObject) {
let dimView = view.viewWithTag(1)
if let dimView = dimView {
removingAnimation(dimView)
Delay.delay(0.4){
dimView.removeFromSuperview()
}
}
}
这是我的延迟 class:
class Delay{
class func delay(delay: Double, block: () -> ()){
let when = dispatch_time(DISPATCH_TIME_NOW, Int64(Int(delay) * Int(NSEC_PER_SEC)))
dispatch_after(when, dispatch_get_main_queue(), block)
}
}
当我 运行 在主线程(这是一个串行线程,应该以串行方式执行任务)上关闭时,我的动画被忽略并且 dimView 立即从视图层次结构中删除。但是,当我 运行 在全局并发线程上关闭时,动画不会被忽略并且代码成功删除了层次结构的 dimView。但这是非法的,因为您必须从主线程访问 UIKit。
能否请您解释一下在主线程上调用闭包时出现的问题?以及我的问题的可能解决方案?
谢谢
问题是您正在将 0.4
的 delay
转换为 Int
,即 0
。我建议将引用替换为
Int64(Int(delay) * Int(NSEC_PER_SEC))
和
Int64(delay * Double(NSEC_PER_SEC))
不过,作为进一步的改进,我不会在经过一定时间后触发删除,而是让动画在完成时告诉你。最简单,你可以使用 block base UIView
animation:
UIView.animateWithDuration(0.2, delay: 0.0, options: .CurveEaseIn, animations: {
dimView.center = CGPoint(x: self.view.center.x, y: 4 * centerY)
}, completion: { finished in
dimView.removeFromSuperview()
})
或者,如果您必须使用 CABasicAnimation
,请指定其 delegate
,然后执行 animationDidStop
委托方法以删除视图:
override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
dimView.removeFromSuperview()
}
顺便说一下,以上所有内容都假设您没有为 dimView
指定自动布局约束。如果您有,而不是通过更改 frame
相关属性来设置动画,您应该修改这些约束,然后设置对 layoutIfNeeded()
.
的调用的动画
要从主视图(子视图 "dims" 父视图,因此称为 dimView)中删除子视图,我使用动画;它基本上将子视图移向屏幕底部并最终移出屏幕:
let centerY = CGRectGetMidY(view.bounds)
let animation: CABasicAnimation = CABasicAnimation(keyPath: "position")
animation.removedOnCompletion = false
animation.fillMode = kCAFillModeForwards
animation.fromValue = NSValue(CGPoint: view.center)
animation.toValue = NSValue(CGPoint: CGPoint(x: view.center.x, y: 4 * centerY))
animation.duration = 0.2
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
dimView.layer.addAnimation(animation, forKey: "DimRemovingAnimation")
然后通过一个事件驱动函数,我这样调用这个动画:
@IBAction func done(sender: AnyObject) {
let dimView = view.viewWithTag(1)
if let dimView = dimView {
removingAnimation(dimView)
Delay.delay(0.4){
dimView.removeFromSuperview()
}
}
}
这是我的延迟 class:
class Delay{
class func delay(delay: Double, block: () -> ()){
let when = dispatch_time(DISPATCH_TIME_NOW, Int64(Int(delay) * Int(NSEC_PER_SEC)))
dispatch_after(when, dispatch_get_main_queue(), block)
}
}
当我 运行 在主线程(这是一个串行线程,应该以串行方式执行任务)上关闭时,我的动画被忽略并且 dimView 立即从视图层次结构中删除。但是,当我 运行 在全局并发线程上关闭时,动画不会被忽略并且代码成功删除了层次结构的 dimView。但这是非法的,因为您必须从主线程访问 UIKit。
能否请您解释一下在主线程上调用闭包时出现的问题?以及我的问题的可能解决方案?
谢谢
问题是您正在将 0.4
的 delay
转换为 Int
,即 0
。我建议将引用替换为
Int64(Int(delay) * Int(NSEC_PER_SEC))
和
Int64(delay * Double(NSEC_PER_SEC))
不过,作为进一步的改进,我不会在经过一定时间后触发删除,而是让动画在完成时告诉你。最简单,你可以使用 block base UIView
animation:
UIView.animateWithDuration(0.2, delay: 0.0, options: .CurveEaseIn, animations: {
dimView.center = CGPoint(x: self.view.center.x, y: 4 * centerY)
}, completion: { finished in
dimView.removeFromSuperview()
})
或者,如果您必须使用 CABasicAnimation
,请指定其 delegate
,然后执行 animationDidStop
委托方法以删除视图:
override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
dimView.removeFromSuperview()
}
顺便说一下,以上所有内容都假设您没有为 dimView
指定自动布局约束。如果您有,而不是通过更改 frame
相关属性来设置动画,您应该修改这些约束,然后设置对 layoutIfNeeded()
.