问题
我触发使用定时器选择UIViews的随机动画。所有动画工作打算,但在其中一种的CALayer的抽签方法计时器选择的退出后调用。
详细说明
为了清晰和简单起见,让我schematise执行的操作。
所有的动画我到目前为止创建工作像预期一样:他们是在现有的子视图/子层或添加到选定的视图层次换新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)
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
}
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
绘制层,但它不工作:调试draw
方法退出后不断达到定制的CALayer类的performAnimation
方法,而应该叫当层的帧被在animatePattern
方法改性。我必须错过的东西很明显,但我目前手忙脚乱,我会很感激一双崭新的眼睛就可以了。
预先感谢您抽出宝贵的时间来考虑这个问题!最好,
您覆盖抽奖(_上下文)作为UIView的可能的CALayer的委托。
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)}
}
}
由于它是经常有这种情况,当你花时间去您的问题写下来,新的理念开始流行起来。事实上,我记得self.setNeedsDisplay()
通知该层需要(重新)绘制的,但它不(重新)绘制一次系统:它会在下一次刷新期间进行。这似乎那么的刷新周期为特定的动画结束后发生。为了克服这个问题,我首先通过调用display
方法,而不是增加了一个呼吁displayIfNeeded
方法后右边的patternLayer边界被设置为,和它的工作,但鉴于@马特评论,我改变了解决方案。它的工作原理也是如此。
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)
}
再次,应该有人想出另一种更优雅的解决方案/解释,请不要犹豫分享!