MEH
MEH

Reputation: 1864

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 !

Upvotes: 0

Views: 690

Answers (3)

Vitaly Migunov
Vitaly Migunov

Reputation: 4457

You can do it like this, just translate your layer alongside with scale animation. To do so you need to create a 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)
}

Upvotes: 1

Duncan C
Duncan C

Reputation: 131471

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

Upvotes: 1

Mohamad Bachir Sidani
Mohamad Bachir Sidani

Reputation: 2099

1- First make the heart shape that will animate a UIView let's name it heartView.

2- self.view.addsubview(heartView) (self.view can be changed to any parent you want)

3- make an invisible button called heartButton and give it the same frame of heartView

4- self.view.addsubview(heartButton) (self.view can be changed to any parent you want)

5- start the heartView animation.

The key point here is not to add the button on the animating view but on their parent (self.view this case) since if the button was on top of the heart and the heart is animating, the button will adopt the animation.

Hope this helps!

Upvotes: 0

Related Questions