问题
我使用Timer在选择的UIView上触发随机动画。所有动画均按预期工作,但在计时器选择器退出后将调用CALayer的draw方法的动画。
详细说明
为了清楚和简化起见,让我示意执行的动作。
到目前为止,我创建的所有动画均按预期工作:它们是现有子视图/子层上CABAsicAnimations的组合,或者是添加到选定视图层次结构中的新动画。它们被编码为UIView扩展,因此可以在任何视图上调用它们,而不必考虑视图或视图所在的视图控制器。嗯,除了一个视图之外,所有其他功能都可以。
我确实已经创建了一个自定义CALayer类,该类包含CALayer上的图形图案。在此自定义类的扩展中,提供了一种对这些模式进行动画处理的方法(请参见下文中的代码)。因此,总而言之,当我到达步骤/方法animate selected view
并运行此特定动画时,这是应发生的情况:
问题:如果使用所有其他动画,则所有图形均在退出animate selected view
步骤/方法之前执行,在这种情况下,将自定义CALayer类绘制在performAnimation
方法退出后被称为 ,这反过来会导致动画崩溃。
我应该补充一点,我已经在一个单独的简化操场上尝试了自定义CALayer类动画,并且效果很好(我将自定义图层添加到了UIViewController的UIView
方法中的viewDidLoad
上,然后在UIViewController的viewDidAppear
方法中调用图层动画。)
代码
animate selected view
步骤/方法调用的方法:
func animatePattern(for duration: TimeInterval = 1) {
let patternLayer = PatternLayer(effectType: .dark)
patternLayer.frame = self.bounds
self.layer.addSublayer(patternLayer)
patternLayer.play(for: duration)
}
(请注意,此方法在UIView扩展中,因此self
在此表示已在其上调用动画的UIView)
简化的自定义CALayer类:
override var bounds: CGRect {
didSet {
self.setNeedsDisplay()
}
// Initializers
override init() {
super.init()
self.setNeedsDisplay()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
init(effectType: EffectType){
super.init()
// sets various properties
self.setNeedsDisplay()
}
// Drawing
override func draw(in ctx: CGContext) {
super.draw(in: ctx)
guard self.frame != CGRect.zero else { return }
self.masksToBounds = true
// do the drawings
}
自定义CALayer类的动画扩展:
func play(for duration: Double, removeAfterCompletion: RemoveAfterCompletion = .no) {
guard self.bounds != CGRect.zero else {
print("Cannot animate nil layer")
return }
CATransaction.begin()
CATransaction.setCompletionBlock {
if removeAfterCompletion.removeStatus {
if case RemoveAfterCompletion.yes = removeAfterCompletion { self.fadeOutDuration = 0.0 }
self.fadeToDisappear(duration: &self.fadeOutDuration)
}
}
// perform animations
CATransaction.commit()
}
到目前为止的尝试
我试图通过在代码中的各个位置插入setNeedsDisplay
/ setNeedsLayout
来强制绘制图层,但是它不起作用:不断调试自定义CALayer类的draw
方法在performAnimation
方法退出之后,而在animatePattern
方法中修改图层的框架时应调用它。我必须想念一些很明显的东西,但是我目前正在圈子里奔跑,不胜感激。
在此先感谢您抽出宝贵的时间来考虑此问题! 最好,
答案 0 :(得分:0)
您可以覆盖draw(_上下文),因为UIView可以是CALayer的委托。
List
答案 1 :(得分:-1)
通常情况下,当您花时间写下您的问题时,就会出现新的想法。实际上,我记得self.setNeedsDisplay()
通知系统需要(重新)绘制该层,但它不会立即(重新)绘制该层:它将在下一次刷新期间完成。这样看来,刷新发生在该特定动画的循环结束之后。为了解决这个问题,我首先在设置patternLayer边界之后立即添加了对display
方法的调用,并且该方法起作用了,但是在给@Matt注释的同时,我通过调用displayIfNeeded
来更改了解决方案。方法代替。也可以。
func animatePattern(for duration: TimeInterval = 1) {
let patternLayer = PatternLayer(effectType: .dark)
patternLayer.frame = self.bounds
self.layer.addSublayer(patternLayer)
// asks the system to draw the layer now
patternLayer.displayIfNeeded()
patternLayer.play(for: duration)
}
同样,如果有人提出另一个更优雅的解决方案/解释,请不要共享!