如何防止 CABasicAnimation 缩放 UIView 中的所有内容?

How to prevent CABasicAnimation from scale all content inside UIView?

我写这个是为了将心跳动画应用到 CAShapeLayer,在这工作正常之后,我需要将它实现在 UIButton (btnTest) 后面而不缩放 UIButton 或任何其他内容。

@IBOutlet weak var btnTest: UIButton!

let btnLayer = CAShapeLayer()

override func viewDidLoad() {
    super.viewDidLoad()
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    btnTest.layer.removeAllAnimations()

    let ovalPath = UIBezierPath(arcCenter: CGPoint(x: btnTest.frame.midX, y: btnTest.frame.midY), radius: 100, startAngle: 0*(CGFloat.pi / 180), endAngle: 360*(CGFloat.pi / 180), clockwise: true)

    btnLayer.path = ovalPath.cgPath
    btnLayer.fillColor = UIColor.red.cgColor
    btnLayer.contentsGravity = "center"
    btnLayer.opacity = 0.3
    self.view.layer.addSublayer(btnLayer)

    let theAnimation = CABasicAnimation(keyPath: "transform.scale.xy")
    theAnimation.duration       = 0.75
    theAnimation.repeatCount    = Float.infinity
    theAnimation.autoreverses   = true
    theAnimation.fromValue      = 1.0
    theAnimation.toValue        = 1.2
    theAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
    self.view.layer.add(theAnimation, forKey: nil)
}

这是这个结果gif

另一个解决方案是更改此行:

self.view.layer.add(theAnimation, forKey: nil)

对此:

btnLayer.add(theAnimation, forKey: nil)

结果是这样的:gif

解决这个问题的任何想法!

1- 首先制作心形,让 UIView 动起来,我们将其命名为 heartView.

2- self.view.addsubview(heartView)self.view可以随便改成parent)

3-制作一个名为heartButton的不可见按钮并给它相同的框架heartView

4- self.view.addsubview(heartButton)self.view可以改成任何你想要的parent)

5-启动heartView动画。

这里的关键点不是在动画视图上添加按钮,而是在它们的 parent 上添加按钮(self.view 这种情况)因为如果 button 位于心脏顶部并且心脏是动画的,按钮将采用动画。

希望对您有所帮助!

您想为您的 btnLayer 制作动画。它从错误的位置设置动画的原因可能是层的 anchorPoint 位于 0,0,它应该设置为 0.5, 0.5.

编辑:

实际上,我认为问题在于您将 btnLayer 放在哪里。您应该使它成为按钮视图层的子层,并为其提供一个作为按钮层边界的框架:

btnTest.layer.addSublayer(btnLayer)
btnLayer.frame = btnTest.layer.bounds

您可以这样做,只需将您的图层与缩放动画一起平移即可。为此,您需要创建一个 CAAnimationGroup。

   override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    btnTest.layer.removeAllAnimations()

    let ovalPath = UIBezierPath(arcCenter: CGPoint(x: btnTest.frame.midX, y: btnTest.frame.midY), radius: 100, startAngle: 0*(CGFloat.pi / 180), endAngle: 360*(CGFloat.pi / 180), clockwise: true)

    btnLayer.path = ovalPath.cgPath
    btnLayer.fillColor = UIColor.red.cgColor
    btnLayer.anchorPoint = CGPoint.init(x: 0.5, y: 0.5)
    btnLayer.contentsGravity = "center"
    btnLayer.opacity = 0.3
    self.view.layer.addSublayer(btnLayer)

    let theAnimation = CABasicAnimation(keyPath: "transform.scale.xy")
    theAnimation.fromValue      = 1.0
    theAnimation.toValue        = 1.2

    let theAnimationTranslationX = CABasicAnimation(keyPath: "transform.translation.x")
    theAnimationTranslationX.fromValue      = btnTest.bounds.minX
    theAnimationTranslationX.toValue        = btnTest.bounds.minX - 40

    let theAnimationTranslationY = CABasicAnimation(keyPath: "transform.translation.y")
    theAnimationTranslationY.fromValue      = btnTest.bounds.minY
    theAnimationTranslationY.toValue        = btnTest.bounds.minY - 80


    let animationGroup = CAAnimationGroup.init()
    animationGroup.duration       = 0.75
    animationGroup.repeatCount    = Float.infinity
    animationGroup.autoreverses   = true
    animationGroup.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
    animationGroup.animations = [theAnimation,theAnimationTranslationX,theAnimationTranslationY]

    btnLayer.add(animationGroup, forKey: nil)
}