Search code examples
iosswift3uibuttoncashapelayercabasicanimation

How to prevent CABasicAnimation from scale all content inside UIView?


I've wrote this to apply heart beat animation to CAShapeLayer, after this worked fine, I need to implement it to be behind UIButton (btnTest) without scaling the UIButton or any other content.

@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)
}

the is this result gif

another solution was changing this line :

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

to this :

btnLayer.add(theAnimation, forKey: nil)

the result of this was this :gif

Any ideas to solve this problem !


Solution

  • You want to animate your btnLayer. The reason it's animating from the wrong place is probably that the layer's anchorPoint is at 0,0, where it should be set to 0.5, 0.5.

    Edit:

    Actually, I think the issue is where you put your btnLayer. You should make it a sublayer of your button view's layer, and give it a frame that's the bounds of the button's layer:

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