问题
我使用计时器在选择的 UIView 上触发随机动画。所有动画都按预期工作,但在定时器选择器退出后调用 CALayer 的绘制方法。
详细说明
为了清楚和简化,让我对执行的操作进行图解。
到目前为止,我创建的所有动画都按预期工作:它们是现有 subview /子层上的 CABasicAnimations 或添加到所选 View 层次结构的新动画的组合。它们被编码为 UIView 扩展,因此可以在任何 View 上调用它们,而不管 View 所在的 View 或 View Controller 如何。好吧,除了一个之外,所有的工作。
我确实创建了一个自定义 CALayer 类,它包含在 CALayer 上绘制图案。在这个自定义类的扩展中,有一个方法可以使这些模式动画化(见下文的代码)。所以总而言之,当我到达步骤/方法时 animate selected view
并运行这个特定的动画,这是应该发生的:
- 调用了一个名为 animatePattern 的方法
- 该方法将自定义的CALayer类添加到选中的 View 中,然后调用该层的动画扩展
问题:如果使用所有其他动画,所有绘图都在 animate selected view
退出之前执行步骤/方法,在那种特殊情况下,自定义 CALayer 类绘制方法在 performAnimation
退出后被调用。方法,进而导致动画崩溃。
我应该补充一点,我已经在一个单独且简化的 Playground 中尝试了自定义 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
中修改层的框架时应调用它方法。我一定错过了一些非常明显的东西,但我目前正在兜圈子,我希望能有一双新的眼睛来看待它。
提前感谢您花时间考虑这个问题! 最好的,
最佳答案
您覆盖 draw(_ context),因为 UIView 可以是 CALayer 的委托(delegate)。
UIView: {
var patternLayer : PatternLayer
func animatePattern(for duration: TimeInterval = 1) {
patternLayer = PatternLayer(effectType: .dark)
patternLayer.frame = self.bounds
self.layer.addSublayer(patternLayer)
}
func draw(_ layer: CALayer, in ctx: CGContext){
layer.draw(ctx)
if NECESSARY { patternLayer.play(for: duration)}
}
}
关于ios - 为什么不早点调用自定义CALayer的draw方法呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54630029/