Search code examples
swiftcabasicanimation

Circle scale animation works a bit weird


I am animating my GMSMarker so that it pulse once in couple seconds.

func addWave()
    {
//        circleView.layer.cornerRadius = size / 2

        //Scale
        let scaleAnimation = CABasicAnimation(keyPath: "transform.scale")
        scaleAnimation.fromValue = 1
        scaleAnimation.toValue = zoom

        //Opacity
        let alphaAnimation = CABasicAnimation(keyPath: "opacity")
        alphaAnimation.toValue = 0.0

        //Corner radius
//        let cornerRadiusAnimation = CABasicAnimation(keyPath: "cornerRadius")
//        cornerRadiusAnimation.fromValue = size / 2
//        cornerRadiusAnimation.toValue = (size * zoom)/2

        //Animation Group
        let animations: [CAAnimation] = [scaleAnimation, alphaAnimation]

        let animationGroup = CAAnimationGroup()
        animationGroup.duration = duration
        animationGroup.animations = animations
        animationGroup.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
        animationGroup.repeatCount = 1
        animationGroup.fillMode = kCAFillModeForwards
        animationGroup.isRemovedOnCompletion = false
        circleView.layer.add(animationGroup, forKey: "group")
    }

The result looks like this:

enter image description here enter image description here

And if I uncomment Corner radius section it looks like this:

enter image description here

So I need an advice.


Solution

  • Based on my observations, I think it must be a issue of wrong path of your CAShapeLayer hence the masking of the circle.

    I just wrote a radar animation, I hope it might help you.

        let scaleAnimation = CABasicAnimation(keyPath: "transform.scale")
        scaleAnimation.fromValue = 0
        scaleAnimation.toValue = 1
    
        let alphaAnimation = CABasicAnimation(keyPath: "opacity")
        alphaAnimation.fromValue = 1
        alphaAnimation.toValue = 0
    
        let animations = CAAnimationGroup()
        animations.duration = 0.8
        animations.repeatCount = Float.infinity
        animations.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
        animations.animations = [scaleAnimation, alphaAnimation]
    
        circleView.layer.add(animations, forKey: "animations")
    

    What I did was, I used two CAShapeLayer (one being the orange marker and other is the rader layer at the back of marker). The animations were applied on the radar layer.

        radarLayer = CAShapeLayer()
        radarLayer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height);
        radarLayer.path = UIBezierPath(rect: radarLayer.frame).cgPath
        radarLayer.fillColor = UIColor.orange.cgColor
        radarLayer.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2)
        radarLayer.cornerRadius = radarLayer.frame.size.width/2
        radarLayer.masksToBounds = true
        radarLayer.opacity = 0
        self.layer.addSublayer(radarLayer)
    
        circleLayer = CAShapeLayer()
        circleLayer.frame = CGRect(x: 0, y: 0, width: 16, height: 16);
        circleLayer.path = UIBezierPath(rect: circleLayer.frame).cgPath
        circleLayer.fillColor = UIColor.orange.cgColor
        circleLayer.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2)
        circleLayer.cornerRadius = circleLayer.frame.size.width/2
        circleLayer.masksToBounds = true
        self.layer.addSublayer(circleLayer)
    

    PS. I'm new to Swift, so enlighten me if I'm wrong somewhere :)

    Example : https://i.sstatic.net/Ejx8Q.jpg