【问题标题】:How do I remove a CAShapeLayer and CABasicAnimation from my UIView?如何从我的 UIView 中删除 CAShapeLayer 和 CABasicAnimation?
【发布时间】:2018-03-27 17:22:34
【问题描述】:

这是我的代码:

@objc func drawForm() {
    i = Int(arc4random_uniform(UInt32(formNames.count)))
    var drawPath = actualFormNamesFromFormClass[i]
    shapeLayer.fillColor = UIColor.clear.cgColor
    shapeLayer.strokeColor = UIColor.black.cgColor
    shapeLayer.lineWidth = 6
    shapeLayer.frame = CGRect(x: -115, y: 280, width: 350, height: 350)

    var paths: [UIBezierPath] = drawPath()
    let shapeBounds = shapeLayer.bounds
    let mirror = CGAffineTransform(scaleX: 1,
                                   y: -1)
    let translate = CGAffineTransform(translationX: 0,
                                      y: shapeBounds.size.height)
    let concatenated = mirror.concatenating(translate)

    for path in paths {
        path.apply(concatenated)
    }

    guard let path = paths.first else {
        return
    }

    paths.dropFirst()
        .forEach {
            path.append($0)
    }

    shapeLayer.transform = CATransform3DMakeScale(0.6, 0.6, 0)
    shapeLayer.path = path.cgPath

    self.view.layer.addSublayer(shapeLayer)

    strokeEndAnimation.duration = 30.0
    strokeEndAnimation.fromValue = 0.0
    strokeEndAnimation.toValue = 1.0
    shapeLayer.add(strokeEndAnimation, forKey: nil)
}

此代码为 shapeLayer 路径的绘制设置动画,但是我在网上找不到有关删除此层并停止此基本动画或删除绘制的 cgPath 的任何信息...任何帮助将不胜感激!

【问题讨论】:

  • 顺便说一句,您可能没有注意到它,但我简化了答案中的代码,您从中获得了此路径构建逻辑。也就是说,您可以将其进一步简化为 let path = UIBezierPath()paths.forEach { path.append($0) }

标签: swift swift-playground cashapelayer cabasicanimation cgpath


【解决方案1】:

你说:

我在网上找不到任何关于删除该层的信息...

removeFromSuperlayer()

shapeLayer.removeFromSuperlayer()

你接着说:

...并停止这个基本动画...

removeAllAnimations:

shapeLayer.removeAllAnimations()

注意,这会立即将strokeEnd(或您正在制作动画的任何属性)更改回其先前的值。如果你想在你停止它的地方“冻结”它,你必须抓住presentation图层(它在动画中间捕获图层的属性),保存适当的属性,然后更新图层的属性您正在停止动画:

if let strokeEnd = shapeLayer.presentation()?.strokeEnd {
    shapeLayer.removeAllAnimations()
    shapeLayer.strokeEnd = strokeEnd
}

最后,你继续说:

...或删除被绘制的cgPath

只需将其设置为nil:

shapeLayer.path = nil

顺便说一句,当您浏览 CAShapeLayerCABasicAnimation 的文档时,不要忘记查看它们的超类的文档,即 CALayerCAAnimation » CAPropertyAnimation , 分别。归根结底,在四处寻找有关某些特定类的属性或方法的文档时,您通常必须深入研究超类以找到相关信息。

最后,Core Animation Programming Guide 是很好的介绍,虽然它的示例是在 Objective-C 中,但所有概念都适用于 Swift。

【讨论】:

    【解决方案2】:

    您可以使用动画委托CAAnimationDelegate 在动画开始或结束时执行附加逻辑。例如,您可能希望在淡出动画完成后从其父层中移除一个层。

    下面的代码取自在层上实现 CAAnimationDelegate 的类,当您调用 fadeOut 函数时,该层的不透明度动画,一旦动画完成,animationDidStop(_:finished:) 将其从其超层中移除。

    extension CALayer : CAAnimationDelegate  {
        func fadeOut() {
            let fadeOutAnimation = CABasicAnimation()
            fadeOutAnimation.keyPath = "opacity"
            fadeOutAnimation.fromValue = 1
            fadeOutAnimation.toValue = 0
            fadeOutAnimation.duration = 0.25
            fadeOutAnimation.delegate = self
            self.add(fadeOutAnimation,
                         forKey: "fade")
        }
    
        public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
            self.removeFromSuperlayer()
        }
    }
    

    【讨论】:

    • delegate 是在动画结束时做某事的好方法。不过,我必须承认,这种特殊的模式 (animation.delegate = self) 总是让我大吃一惊,因为与大多数代表不同,CAAnimation delegatestrong 参考。你在这里很好,因为isRemovedOnCompletiontrue,但你是一个远离强引用循环的微不足道的属性设置。您的代码在这里没有任何问题,只是对尝试此模式的未来读者的警告。
    • 这很聪明。结合在实例上调用 setValue(::) 来记录标签信息,这是非常有用的方法。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多