6
votes

I'm applying a CGAffineTransform animation to a UIView with the following code:

UIView.animate(withDuration: 0.5, delay: delay, options: [.autoreverse, .repeat], animations: {
    elementView.transform = CGAffineTransform(scaleX: 1.0, y: 0.4)
}) { (finished) in

}

The UIView scales correctly in the animation, but I also have the UIView's corner radius set to perfectly round the top and bottom of the view.

enter image description here

The problem is, when the scaling animation occurs, the corner radius of my UIView is "squished":

enter image description here

How can I ensure the corner radius remains perfectly rounded, while maintaining the scaling animation?

3

3 Answers

4
votes

I think your best bet is to just change the frame property of elementView:

UIView.animate(withDuration: 0.5, delay: delay, options: [.autoreverse, .repeat], animations: {
    elementView.frame = CGRect(x: elementView.frame.origin.x, y: elementView.frame.origin.y, width: elementView.frame.size.width, height: elementView.frame.size.height * 0.4)
}) { (finished) in

}

or if you're using auto-layout:

heightContraint.constant = heightConstraint * 0.4
UIView.animate(withDuration: 0.5, delay: delay, options: [.autoreverse, .repeat], animations: {
    elementView.layoutIfNeeded()
}) { (finished) in

}

Either way should keep your corner radius while shortening the view.

3
votes

The transformation scales down the corner radius too - I would expect it to behave that way. If you want to get the same result, just with the correct corner radius, you will have to use a different approach.

I myself would use a height constraint instead:

let heightConstraint = elementView.heightAnchor.constraint(equalToConstant: 100)
heightConstraint.isActive = true

And then scale down the constant:

heightConstraint.constant = heightConstraint.constant * 0.4 // (or set to constant directly)
elementView.superView.setNeedsLayout()
UIView.animate(withDuration: 0.5, delay: delay, options: [.autoreverse, .repeat], animations: {
    elementView.superView.layoutIfNeeded()
}) { (finished) in

}
2
votes

Solution:

UIView.animate(withDuration: 0.5, delay: delay, options: [.autoreverse, .repeat], animations: {
    elementView.transform = CGAffineTransform(scaleX: 1.0, y: 0.4)
    elementView.layer.cornerRadius /= 0.4 // <-- solution
}) { (finished) in

}

Playground version:

import UIKit
import PlaygroundSupport

let w: CGFloat = 10
let h: CGFloat = 100
let radius = w/2
let elementView = UIView(frame: CGRect(x: 10, y: 10, width: w, height: h))
elementView.backgroundColor = .red
elementView.layer.cornerRadius = radius

UIView.animate(withDuration: 0.5, delay: 0, options: [.autoreverse, .repeat], animations: {
    elementView.transform = CGAffineTransform(scaleX: 1.0, y: 0.4)
    elementView.layer.cornerRadius =/ 0.4 // <-- solution
}) { (finished) in

}

PlaygroundPage.current.liveView = elementView