How to provide a cornerRadius to a UIImageView with contentMode set to scaleAspectFit

135 Views Asked by At

I have an image which has contentMode set to scaleAspectFit with a cornerRadius but i don't get the rounded corner but when I set the contentMode to scaleAspectFill it works. My question is i still need my contentMode to be set to scaleAspectFit and also have my cornerRadius show. Below is my sample code.

private let imageView: UIImageView = {
        let image = UIImageView()
        image.translatesAutoresizingMaskIntoConstraints = false
        image.clipsToBounds = true
        image.image = UIImage(named: "105")
        image.layer.cornerRadius = 30
        image.contentMode = .scaleAspectFit
        return image
    }()

override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        
        setUpConstraints()
    }

private func setUpConstraints(){
        view.addSubview(btnClose)
        view.addSubview(lblRateIT)
        view.addSubview(lblLoveIT)
        view.addSubview(redBottomView)
        view.addSubview(imageView)
        
        NSLayoutConstraint.activate([
            imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 50),
            imageView.topAnchor.constraint(equalTo: lblLoveIT.bottomAnchor, constant: 20),
            imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -50),
            imageView.bottomAnchor.constraint(equalTo: redBottomView.topAnchor, constant: -20)
        ])
    }
1

There are 1 best solutions below

0
DonMag On

Without knowing what else you might be wanting to do with this, the most straight-forward approach is to use constraints that match the aspect ratio of the image itself.

So, we can:

  • create a "container" UIView to hold the imageView
  • constrain the image view to max width and height of the container
  • center the image view in the container
  • constrain the height of the image view equal to the width of the image view, with a multiplier of image.size.height / image.size.width

Using these 3 sample images - horizontal / square / vertical:

enter image description here

enter image description here

enter image description here

and this example view controller:

class ViewController: UIViewController {
    
    let imageOptions: [String] = ["Horizontal", "Square", "Vertical"]
    lazy var segCtrl = UISegmentedControl(items: imageOptions)
    
    let imgView = UIImageView()
    
    // "container" for the image view
    let imgContainerView = UIView()

    // we'll modify this when we change the image
    var aspectConstraint: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .systemBackground
        
        imgView.contentMode = .scaleAspectFit
        imgView.layer.cornerRadius = 30.0
        imgView.layer.masksToBounds = true

        imgContainerView.backgroundColor = .yellow
        
        segCtrl.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(segCtrl)
        
        imgContainerView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(imgContainerView)
        
        imgView.translatesAutoresizingMaskIntoConstraints = false
        imgContainerView.addSubview(imgView)
        
        let g = view.safeAreaLayoutGuide
        
        // make image view as wide and as tall as possible
        //  fitting in the targetRectView
        //  and using aspect ratio of the UIImage
        
        let ivW = imgView.widthAnchor.constraint(equalTo: imgContainerView.widthAnchor)
        ivW.priority = .required - 1
        
        let ivH = imgView.heightAnchor.constraint(equalTo: imgContainerView.heightAnchor)
        ivH.priority = .required - 1
        
        // we haven't loaded an image yet, so let's start with 1:1
        aspectConstraint = imgView.heightAnchor.constraint(equalTo: imgView.widthAnchor, multiplier: 1.0)

        NSLayoutConstraint.activate([
            
            segCtrl.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            segCtrl.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            segCtrl.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            segCtrl.heightAnchor.constraint(equalToConstant: 40.0),

            // let's put the container view below the segmented control
            //  with 60-points "padding" on all 4 sides
            imgContainerView.topAnchor.constraint(equalTo: segCtrl.bottomAnchor, constant: 60.0),
            imgContainerView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 60.0),
            imgContainerView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -60.0),
            imgContainerView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -60.0),
            
            imgView.centerXAnchor.constraint(equalTo: imgContainerView.centerXAnchor),
            imgView.centerYAnchor.constraint(equalTo: imgContainerView.centerYAnchor),

            imgView.widthAnchor.constraint(lessThanOrEqualTo: imgContainerView.widthAnchor),
            imgView.heightAnchor.constraint(lessThanOrEqualTo: imgContainerView.heightAnchor),
            
            ivW, ivH, aspectConstraint,
            
        ])
        
        segCtrl.addTarget(self, action: #selector(segChanged(_:)), for: .valueChanged)

    }
    
    @objc func segChanged(_ segC: UISegmentedControl) {
        updateImage()
    }
    func updateImage() {
        
        let idx = segCtrl.selectedSegmentIndex
        let imgName: String = "sample" + imageOptions[idx]
        
        guard let img = UIImage(named: imgName) else {
            fatalError("Could not load image: \(imgName)")
        }
        imgView.image = img
        
        // we need to update the aspect ratio height constraint
        aspectConstraint.isActive = false
        aspectConstraint = imgView.heightAnchor.constraint(equalTo: imgView.widthAnchor, multiplier: img.size.height / img.size.width)
        aspectConstraint.isActive = true

    }
}

We get this output at start (no image set):

enter image description here

then for Horizontal / Square / Vertical images:

enter image description here

enter image description here

enter image description here