iOS: frame.size.width/2 doesn't produce a circle on every device
You can create an extension to apply the mask and border straight to your image so it will always work disregarding the screen size / scale:
edit/update:
Xcode 11 • Swift 5 or later
extension UIImage {
var circleMask: UIImage? {
let square = CGSize(width: min(size.width, size.height), height: min(size.width, size.height))
let imageView = UIImageView(frame: .init(origin: .init(x: 0, y: 0), size: square))
imageView.contentMode = .scaleAspectFill
imageView.image = self
imageView.layer.cornerRadius = square.width/2
imageView.layer.borderColor = UIColor.white.cgColor
imageView.layer.borderWidth = 5
imageView.layer.masksToBounds = true
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, scale)
defer { UIGraphicsEndImageContext() }
guard let context = UIGraphicsGetCurrentContext() else { return nil }
imageView.layer.render(in: context)
return UIGraphicsGetImageFromCurrentImageContext()
}
}
imgAvatar.image = yourImage.circleMask
Well, Autolayout should be the issue. As it can be seen the height of the imgAvatar
on right is greater than the height of the imgAvatar
on left.
The size of imgAvatar
on right is 190 x 190 and the one on left is 200 x 200, but on the left the corner radius which you are setting is 190/2 i.e. 95px whereas it should be 100px.
Kindly set Height & Width Constraint in your nib file for imgAvatar
, if you do not want the imgAvatar to resize by 1:1.
- Select imgAvatar in your nib.
- Editor > Pin > Height
- Select imgAvatar in your nib.
- Editor > Pin > Width
OR
Try moving your code to viewDidLayoutSubviews
OR
Subclass your UIImageView
and set its corner radius in its awakeFromNib
method
Kindly let us know if it worked. Thanks!
If you test in iOS8.3, you should call layoutIfNeed
on your UI object before get its frame. Please read iOS8.3 Release notes
For example:
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
// code that sets up the button, but doesn’t yet add it to a window
CGRect titleFrame = button.titleLabel.frame;
// code that relies on the correct value for titleFrame
You now need:
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
// code that sets up the button, but doesn’t yet add it to a window
[button layoutIfNeeded]; // This is also safe pre-iOS 8.3
CGRect titleFrame = button.titleLabel.frame;
// code that relies on the correct value for titleFrame
It's said that for UIButton and sub-classes but you can try it also with your UI object.
When linking against iOS 8.3, any code that relies on layout information (such as the frame) of a UIButton subview when the button is not in the window hierarchy will need to send layoutIfNeeded to the button before retrieving layout information (such as button.titleLabel.frame) to ensure that the layout values are up to date.
Also, as the imgAvatar's cornerRadius was set to 1/2 of imgFrame's size, you will get a circle only if that cornerRadius value = 1/2 of imgAvatar's width (and height).
So, after the call:
imgAvatar.layer.cornerRadius = imgFrame.frame.size.width/2
verify :
- frame size of imgAvatar and its cornerRadius
- be sure that image is squared
The problem is that when the circle is applied, the bounds of the view are still considered the default (320x480) and so if you have set constraints related to the screen, the image will be bigger on iPhone 6/6+ for instance.
There are various solution, but if you want a fast one, just put your code:
imgAvatar.layer.cornerRadius = imgFrame.frame.size.width/2
in - viewDidLayoutSubviews
in your view controller or in - layoutSubviews
in your view, checking before if the cornerRadius is different from the width/2 of the image's frame. Something like this:
if (imgAvatar.layer.cornerRadius != imgFrame.frame.size.width/2) {
imgAvatar.layer.cornerRadius = imgFrame.frame.size.width/2
}