How to keep a round imageView round using auto layout?

How do I turn a rectangular image view into a circular image view that can hold shape in auto layout without setting width and height restraints? Thereby allowing the imageView to define it’s size, and size bigger and smaller relative to objects around it with leading, trailing, top, and bottom constraints.

I asked a similar question the other day, but I think this might be posed in a more concise way. Thanks so much!

  • Is key-value observation (KVO) available in Swift?
  • Xcode 4 automatically generates iVars when using @property,where can I find the official doc for this feature?
  • Can I cast a metaclass object to a protocol type in Swift?
  • Receipt alignment is not working properly in swift
  • Voice over doesn't read phone number properly
  • IOS: set a default language in xcode for my app
  • EDIT

    Ok, I started over to make this as simple as possible. I have a view named “Cell” and a UIImageView named “dog” within the cell, and that’s it. I don’t have “unable to simultaneously satisfy constraints” in the console anymore, just two simple views using auto layout. I’m still trying to use this code to round the UIImageView:

    profileImageView.layer.cornerRadius = profileImageView.frame.size.width / 2
    profileImageView.clipsToBounds = true
    

    Here is the cell constraint setup:

    screenshot 1

    Here is the profile pic constraint setup:

    screenshot 2

    Here is the result without the code, no rounding, but nice and square:

    screenshot 3

    Here is the result with the code to round:

    screenshot 4

    This makes no sense to me, because without the rounding code the image is square, and with the code it’s diamond shaped. If it’s square shouldn’t it be a circle with no issues?

    EDIT 2

    Here’s what happens when I remove the bottom constraint and add a multiplier of .637 for equal height to superview.

    screenshot 5

    8 Solutions Collect From Internet About “How to keep a round imageView round using auto layout?”

    Unfortunately you cannot do this using cornerRadius and autolayout — the CGLayer is not affected by autolayout, so any change in the size of the view will not change the radius which has been set once causing, as you have noticed, the circle to lose its shape.

    You can create a custom subclass of UIImageView and override layoutSubviews in order to set the cornerRadius each time the bounds of the imageview change.

    EDIT

    An example might look something like this:

    class Foo: UIImageView {
        override func layoutSubviews() {
            super.layoutSubviews()
    
            let radius: CGFloat = self.bounds.size.width / 2.0
    
            self.layer.cornerRadius = radius
        }
    }
    

    And obviously you would have to constrain the Foobar instance’s width to be the same as the height (to maintain a circle). You would probably also want to set the Foobar instance’s contentMode to UIViewContentMode.ScaleAspectFill so that it knows how to draw the image (this means that the image is likely to be cropped).

    Setting radius in viewWillLayoutSubviews will solve the problem

    override func viewWillLayoutSubviews() {
      super.viewWillLayoutSubviews()
      profileImageView.layer.cornerRadius = profileImageView.frame.height / 2.0
    }
    

    create new interface in your .h file like

     @interface cornerClip : UIImageView
    
     @end
    

    and implementation in .m file like

    @implementation cornerClip
    
    
    -(void)layoutSubviews
    {
    [super layoutSubviews];
    {
        CGFloat radius = self.bounds.size.width / 2.0;
    
        self.layer.cornerRadius = radius;
    }
    
    }
    @end
    

    now just give class as “cornerClip” to your imageview.
    100% working… Enjoy

    It seems when you add one view as a subview of another that netted view will not necessarily have the same height as its superview. That’s what the problem seems like. The solution is to not add your imageView as a subview, but have it on top of your backgroundView. In the image below I’m using a UILabel as my backgroundView.

    screenshot

    Also in your case, when you’re setting the cornerRadius use this: let radius: CGFloat = self.bounds.size.height / 2.0.

    With my hacky solution you’ll get smooth corner radius animation alongside frame size change.

    Let’s say you have ViewSubclass : UIView. It should contain the following code:

    class ViewSubclass: UIView {
        var animationDuration : TimeInterval?
        let imageView = UIImageView()
        //some imageView setup code
    
        override func layoutSubviews() {
            super.layoutSubviews()
    
            if let duration = animationDuration {
                let anim = CABasicAnimation(keyPath: "cornerRadius")
                anim.fromValue = self.imageView.cornerRadius
                let radius = self.imageView.frame.size.width / 2
                anim.toValue = radius
                anim.duration = duration
                self.imageView.layer.cornerRadius = radius
                self.imageView.layer.add(anim, forKey: "cornerRadius")
            } else {
                imageView.cornerRadius = imageView.frame.size.width / 2
            }
    
            animationDuration = nil
        }
    }
    

    An then you’ll have to do this:

    let duration = 0.4 //For example
    instanceOfViewSubclass.animationDuration = duration
    UIView.animate(withDuration: duration, animations: { 
        //Your animation
        instanceOfViewSubclass.layoutIfNeeded()
    })
    

    It’s not beautiful, and might not work for complex multi-animations, but does answer the question.

    I have same problem, and Now I get what happened here, hope some ideas can help you:
    there are something different between the tows:

    1. your profileImageView in storyboard
    2. your profileImageView in viewDidLoad

    the size of bound and frame is different when viewDidLoad and in storyboard,just because view is resize for different device size.
    You can try it print(profileImageView.bounds.size) in viewDidLoad and viewDidAppear you will find the size in viewDidLoad you set cornerRadius is not the real “running” size.

    a tips for you:
    you can use a subClass of ImageView to avoid it, or do not use it in storyboard,

    Add a 1:1 aspect ratio constraint to the imageView for it to remain circular, despite any height or width changes.

    Can be easily done by creating an IBOutlet for the constraint which needs to be changed at runtime. Below is the code:

    1. Create a IBOutlet for the constraint that needs to be changed at run time.

      @IBOutlet var widthConstraint: NSLayoutConstraint!
      
    2. Add below code in viewDidLoad():

      self.widthConstraint.constant = imageWidthConstraintConstant()
      

    Below function determines for device types change the width constraint accordingly.

    func imageWidthConstraintConstant() -> CGFloat {
    
        switch(self.screenWidth()) {
    
        case 375:
            return 100
    
        case 414:
            return 120
    
        case 320:
            return 77
    
        default:
            return 77
        }
    }