ios - 为什么不早点调用自定义CALayer的draw方法呢?

标签 ios swift animation timer draw

问题

我使用计时器在选择的 UIView 上触发随机动画。所有动画都按预期工作,但在定时器选择器退出后调用 CALayer 的绘制方法。

详细说明

为了清楚和简化,让我对执行的操作进行图解。

Cycle

到目前为止,我创建的所有动画都按预期工作:它们是现有 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/

相关文章:

iphone - setEnabled 不适用于 UIButton

ios - 无法通过对象链接查询 NSData 属性

ios - 使用 Alamofire 和不记名 token 序列化对象

ios - TextView 不显示在 ScrollView 上

带有 SpriteKit 的 iOS 通用设备应用程序,如何为所有 View 缩放节点?

javascript - 添加新的 DOM 子元素时显示动画

ios - 使用嵌入在动态框架中的第三方框架

ios - UIAlertController addAction 不起作用

css - 应该是:hover pseudo state style change work after CSS animation completes

wpf - 使用 MVVM 从事件触发动画