Search code examples
iossnapkit

How can I adjust the the size of the circle to dynamically adjust to the width and height of any iPhone?


I am using snap kit to set out constraints. The first image is what I'm trying to achieve with the code below. How can I set the constraints off the circle's width and height to be dynamic on any iPhone screen ?

 profileImage = UIImageView()
        profileImage.layer.borderWidth = 2
        profileImage.layer.borderColor = UIColor.lightBlue.cgColor
        profileImage.layer.cornerRadius = 130
        profileImage.clipsToBounds = true
        profileImage.layer.masksToBounds = true
        let tapGesture = UITapGestureRecognizer(target: self, action:#selector((tappedImage)))
        profileImage.addGestureRecognizer(tapGesture)
        profileImage.isUserInteractionEnabled = true
        profileImage.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(profileImage)
        profileImage.snp.makeConstraints { (make) in
            make.centerX.equalToSuperview()
            make.top.equalTo(titleLabel.snp.bottom).offset(topMargin*2)
            make.width.height.equalTo(view.snp.width).multipliedBy(0.71)
       }   

enter image description here

enter image description here


Solution

  • Couple points...

    First, 71% of the view width will probably be too big. Start around 50% and adjust to your liking.

    You are using .cornerRadius = 130 but your imageView may not be that size (certainly not on different devices), so you want to set the corner radius to one-half the width of the image view (or height, doesn't matter since it will be a square 1:1 ratio).

    You could wait until viewDidLayoutSubviews() to find out the run-time size of the image view, but if your image view ends up as a subview of another view, it won't be set at that point either.

    Much easier to create a very simple UIImageView subclass:

    class ProfileImageView: UIImageView {
        
        override func layoutSubviews() {
            super.layoutSubviews()
            layer.borderWidth = 2
            layer.borderColor = UIColor.systemBlue.cgColor
            layer.cornerRadius = bounds.width * 0.5
            clipsToBounds = true
            layer.masksToBounds = true
        }
    
    }
    

    Then your view controller looks like this:

    class ViewController: UIViewController {
        
        var profileImage: ProfileImageView!
        
        // your top margin value
        let topMargin: CGFloat = 20
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            profileImage = ProfileImageView()
    
            if let img = UIImage(named: "sampleProfilePic") {
                profileImage.image = img
            }
    
            profileImage.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(profileImage)
            
            // respect safe-area
            let g = view.safeAreaLayoutGuide
    
            // this should give the same layout as your "snap" constraints
            NSLayoutConstraint.activate([
                // center horizontally
                profileImage.centerXAnchor.constraint(equalTo: g.centerXAnchor),
                // your topMargin value * 2 from safe-area top
                profileImage.topAnchor.constraint(equalTo: g.topAnchor, constant: topMargin * 2.0),
                // width
                //  71% of width of safe-area is probably too wide
                //  try starting at 50%
                profileImage.widthAnchor.constraint(equalTo: g.widthAnchor, multiplier: 0.50),
                // 1:1 ratio (square)
                profileImage.heightAnchor.constraint(equalTo: profileImage.widthAnchor),
            ])
    
            //      profileImage.snp.makeConstraints { (make) in
            //          make.centerX.equalToSuperview()
            //          make.top.equalTo(titleLabel.snp.bottom).offset(topMargin*2)
            //          make.width.height.equalTo(view.snp.width).multipliedBy(0.71)
            //      }
    
            let tapGesture = UITapGestureRecognizer(target: self, action:#selector((tappedImage)))
            profileImage.addGestureRecognizer(tapGesture)
            profileImage.isUserInteractionEnabled = true
    
        }
    
    }
    

    Whenever the size of your profileImage view changes, the ProfileImageView class' layoutSubviews() will automatically set the corner radius appropriately.