Search code examples
iosanimationcore-animation

Change the frame of an UIView and update cornerRadius


In my app I am using UIView subclasses to display all kinds of information. I want this views to appear round, so I set the cornerRadius on the views layer to self.bounds.size.width / 2.

This works as expected, until I try to animate them. I animate my view using the UIView.animateWithDuration, for example:

UIView.animateWithDuration(0.2, animations: { () -> Void in

    self.myView.frame = CGRectInset(self.myView.frame, -20, -20);

}) { (done) -> Void in

}

I would like my view to also update the cornerRadius of the layer in the same animation (or a seperate animation, because the cornerRadius changes aren't animated with the animateWithDuration.

Here is what I already tried:

  • Subclass a CALayer, which draws a circle and just put that on top of MyView.layer.
  • Perform a CABasicAnimation while the UIView.animatewithDuration is running

But all of them result in screwed results, because either the bounds aren't updated yet, or the resize of the added CALayer is done before the other animation is finished. I want it to be a smooth transition.


Solution

  • func changeBounds()
    {
        let animation = CABasicAnimation()
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        animation.fromValue = NSValue(CGRect: self.theView.frame)
        animation.toValue = NSValue(CGRect: CGRectInset(self.theView.frame, 40, 40))
        animation.duration = 1.0
        self.theView.layer.addAnimation(animation, forKey: "bounds")
    
        CATransaction.begin()
        CATransaction.setDisableActions(true)
        self.theView.layer.frame = CGRectInset(self.theView.frame, 40, 40)
        CATransaction.commit()
    }
    
    func changeCornerRadius()
    {
        let animation = CABasicAnimation(keyPath:"cornerRadius")
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        animation.fromValue = 0
        animation.toValue = self.theView.frame.size.width/2
        animation.duration = 1.0
        self.theView.layer.addAnimation(animation, forKey: "cornerRadius")
        self.theView.layer.cornerRadius = self.theView.frame.size.width/2
    }
    

    This seems to work for me, just call like this.

    self.changeBounds()
    self.changeCornerRadius()
    

    Set the animation key to "bounds" instead of "frame". Or you can add these two animation to an animation group.