skip to Main Content

I’ve created a custom UIView with a subview containing several square subviews which are sized using layout constraints. I’d like for each subview to be circular so I’m holding a reference to the view in an array, then iterating through the array of views in the layoutSubviews method and applying a corner radius that is half the view.bounds.height.

image showing main view, content view, then three circular views inside

The problem is, this only works 70% of the time. Sometimes the view doesn’t seem to know its bounds and the views are rendered as square.

image showing main view, content view, then three square views inside

I’m probably approaching this all wrong… does anyone have any advice for me? Where is it safe to apply the corner radius so that it always renders as a perfect circle?

Thanks

3

Answers


  1. You can apply the corner radius inside the layoutSubviews() method

    override func layoutSubviews() {
        super.layoutSubviews()
        // This is the place to apply corner radius
    }
    
    Login or Signup to reply.
  2. The most reliable way to manage this is to subclass UIView and let it handle its own rounding.

    For example:

    class RoundView: UIView {
        override func layoutSubviews() {
            super.layoutSubviews()
            // this assumes constraints keep
            //  self at a 1:1 ratio (square)
            layer.cornerRadius = bounds.height * 0.5
        }
    }
    

    This simple controller example:

    class RoundDemoVC: UIViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            let colors: [UIColor] = [
                .systemRed, .systemGreen, .systemBlue
            ]
            let widths: [CGFloat] = [
                200, 140, 140
            ]
            let xPos: [CGFloat] = [
                20, 120, 180
            ]
            let g = view.safeAreaLayoutGuide
            for i in 0..<colors.count {
                let v = RoundView()
                v.backgroundColor = colors[i]
                view.addSubview(v)
                v.translatesAutoresizingMaskIntoConstraints = false
                v.widthAnchor.constraint(equalToConstant: widths[i]).isActive = true
                // make it square
                v.heightAnchor.constraint(equalTo: v.widthAnchor).isActive = true
                v.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: xPos[i]).isActive = true
                v.centerYAnchor.constraint(equalTo: g.centerYAnchor).isActive = true
            }
            
        }
        
    }
    

    Produces this output:

    enter image description here

    No need to iterate through subviews and setting values based on frame sizes… all you need to do is set the size/position constraints.

    Login or Signup to reply.
  3. Donmag’s example is cool.Also, you can do it this way without writing code to layoutsubview. You must add this settings after adding the constraints of the subviews in for iteration.

     .......
     ....... // constraint settings
    
     subView.layoutIfNeeded()
     subView.layer.cornerRadius = subView.frame.size.height/2
        
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search