Search code examples
iosswiftcashapelayercabasicanimation

CABasicAnimation circle CAShapeLayer moving across the map instead of scaling


I'm trying to create an animation in which a view is hidden . At first it starts at a point on the screen (150 for example) and scales up until it fits the whole screen. Here is what I've tried

public func testAnimation(anchor : CGRect){
    self.isHidden = false
    let mask = CAShapeLayer()
    let radius = 15
    mask.path = UIBezierPath(roundedRect: CGRect(x: 150,y: 150, width:  Double(radius), height: Double(radius)), cornerRadius: CGFloat(radius/2)).cgPath
    mask.position = CGPoint(x: 150,y: 150 )
    mask.fillColor = UIColor.blue.cgColor

    self.layer.mask = mask
    let oldBounds = mask.bounds
    let newBounds = CGRect.init(x: 150,y: 150,width: 1600,height: 1600)
    let revealAnimation = CABasicAnimation(keyPath: "bounds")
    revealAnimation.fromValue = NSValue(cgRect: oldBounds)
    revealAnimation.toValue = NSValue(cgRect: newBounds)
    revealAnimation.duration = 5

    //Keep the bounds after the animation completes.
    mask.bounds = newBounds
    mask.add(revealAnimation, forKey: "revealAnimation")
}

The problem with this snippet is that it causes a small circle to move in the screen instead of making the circle grow bigger in size. I used the code found here : http://blog.ericd.net/2015/10/22/swift-animating-a-mask-for-a-uiview/ (showUnderView function) and it worked like a charm. I swapped the CALayer to CAShapeLayer to get the circle effect but it doesn't work .


Solution

  • Animating the bounds of a CALayer would have worked but here you are using a CAShapeLayer. Setting new bounds won't redraw and scale the shape.

    Instead you should try animating the shape directly :

    let finalRadius: CGFloat = 1600
    let finalPath = UIBezierpath(roundedRect: CGRect(x: 150, y: 150, width: finalRadius, height: finalRadius), cornerRadius: finalRadius / 2).cgPath
    
    let revealAnimation = CABasicAnimation(keyPath: "path")
    revealAnimation.toValue = finalPath
    revealAnimation.duration = 5
    mask.add(revealAnimation, forKey: "revealAnimation")
    

    This will redraw the shape with the wanted size.

    If you want to keep the shape centered, you could animate the position at the same time.