Home > database >  How to provide a cornerRadius to a UIImageView with contentMode set to scaleAspectFit
How to provide a cornerRadius to a UIImageView with contentMode set to scaleAspectFit

Time:12-28

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)
        ])
    }

CodePudding user response:

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

CodePudding user response:

When you aspectFit the content mode of the image, swift fits the image into the imageview in a way that preserves all the proportions. When you give an extra corner radius, the imageview is out of rectangular shape, so it can't fit the photo proportionally. Therefore, contentMode aspectFit can give corner radius values ​​as much as it can fit the screen by preserving the proportions of the photo it is.

Briefly , you can think contentMode = .aspectFit priority is bigger than cornerRadius.it can give cornerRadius again, but this will be as much as the amount of space left after the photo fits into the component proportionally.

For example, let's say 5 units. In this case, if you give the cornerRadius at 5 or 1000, it will remain as 5 units.

In summary , it will not be healthy to use cornerRadius and aspectFit together. I recommend you to change contentMode to scaleAspectFill

  • Related