1

I am trying to add image view in vertical stack view but also at the same time I want to have it in square i.e. it should be equal in width and height.

Any help on how can I make this imageview square?

reference pic attached here. Stack view consist of: imageview and title label

enter image description here

iAsh
  • 447
  • 6
  • 19
  • Do you want the image view only as a square in a vertical stack view or the image view and label together need to be a square ? If you can add an image of what you want your desired output to be, that would help – Shawn Frank Jan 26 '22 at 10:40
  • I want to circle the image view. Label can be rectangle. But to have circular image i want to add square image. My image is very small so will be adding coloured background to it. Any help is really appreciated. – iAsh Jan 26 '22 at 18:03

1 Answers1

0

I would approach the View hierarchy a little bit differently to achieve what you want.

You seem to have

  1. a background UIView
  2. a UIImageView on top of the background view which needs to be a square
  3. A UILabel below the background view

It will be quite difficult to get views to overlap using stack views.

What I suggest is to create a custom UIView with the UIView, UIImageView and the UILabel and put these custom views inside a stack view.

Inside your custom view implementation, you need to figure out how to make the UIImageView a square.

Here is how I implement this custom view:

class CustomView: UIView
{
    private var imageView: UIImageView!
    private let someView = UIView()
    private let label = UILabel()
    
    init()
    {
        super.init(frame: .zero)
        configureSubView()
        configureImageView()
        configureLabel()
    }
    
    required init?(coder: NSCoder)
    {
        fatalError("init(coder:) has not been implemented")
    }
    
    // Configure the background view behind the image
    private func configureSubView()
    {
        someView.backgroundColor = randomColor()
        someView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(someView)
        
        // The background view pins to the edges of the custom view
        // and has a height of 70% of the custom view. Adjust these as
        // you see fit
        someView.leadingAnchor.constraint(equalTo: leadingAnchor)
            .isActive = true
        
        someView.topAnchor.constraint(equalTo: topAnchor)
            .isActive = true
        
        someView.trailingAnchor.constraint(equalTo: trailingAnchor)
            .isActive = true
        
        someView.heightAnchor.constraint(equalTo: heightAnchor,
                                         multiplier: 0.7).isActive = true
    }
    
    private func configureImageView()
    {
        // Replace with your image here
        if let image = UIImage(systemName: "scribble")?
            .withTintColor(randomColor(), renderingMode: .alwaysOriginal)
        {
            // Assume image is a square and get dimension of a side
            let side = image.size.width
            
            // Initialize your image with the UIImage
            imageView = UIImageView(image: image)
            
            // added bg color so you can see impact of making it circular
            imageView.backgroundColor = randomColor()
            
            imageView.translatesAutoresizingMaskIntoConstraints = false
            someView.addSubview(imageView)
            
            // Auto layout constraints to make it a square
            imageView.widthAnchor.constraint(equalToConstant: side)
                .isActive = true
            
            imageView.heightAnchor.constraint(equalToConstant: side)
                .isActive = true
            
            imageView.centerXAnchor.constraint(equalTo: someView.centerXAnchor)
                .isActive = true
            
            imageView.centerYAnchor.constraint(equalTo: someView.centerYAnchor)
                .isActive = true
            
            // apply your corner radius to make image view a circle
            imageView.layer.cornerRadius = side / 2
            imageView.clipsToBounds = true
        }
    }
    
    // Configure the label to be below the background view
    private func configureLabel()
    {
        label.text = "Title"
        label.textColor = randomColor()
        label.backgroundColor = randomColor()
        label.textAlignment = .center
        label.translatesAutoresizingMaskIntoConstraints = false
        addSubview(label)
        
        label.leadingAnchor.constraint(equalTo: leadingAnchor)
            .isActive = true
        
        label.topAnchor.constraint(equalTo: someView.bottomAnchor)
            .isActive = true
        
        label.trailingAnchor.constraint(equalTo: trailingAnchor)
            .isActive = true
        
        label.bottomAnchor.constraint(equalTo: bottomAnchor)
            .isActive = true
    }
    
    // https://stackoverflow.com/a/21130486/1619193
    // You can ignore this function
    private func randomColor() -> UIColor
    {
        let red = CGFloat(arc4random_uniform(256)) / 255.0
        let blue = CGFloat(arc4random_uniform(256)) / 255.0
        let green = CGFloat(arc4random_uniform(256)) / 255.0
        
        return UIColor(red: red, green: green, blue: blue, alpha: 1.0)
    }
}

Then here is how I put the custom views into a vertical stack view:

class StackViewTestViewController: UIViewController
{
    // Stack view to hold the custom views
    let verticalStackView = UIStackView()
    
    // Set how many ever you want
    let numberOfCustomViews = 3
    
    // Set width of each custom view in stack view
    let heightOfCustomView: CGFloat = 80
    
    // Set width of each custom view
    let widthOfCustomView: CGFloat = 100
    
    // Set padding between custom views in the stack view
    let padding: CGFloat = 20
    
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        title = "Square Stack View"
        view.backgroundColor = .white
        
        configureStackView()
        addCustomViewsToStackView()
    }
    
    private func configureStackView()
    {
        verticalStackView.axis = .vertical
        verticalStackView.distribution = .equalSpacing
        
        verticalStackView.translatesAutoresizingMaskIntoConstraints = false
        
        view.addSubview(verticalStackView)
        
        // Calculate the height of the stack view depending on the custom views
        let heightOfStackView = (CGFloat(numberOfCustomViews) * heightOfCustomView)
            + padding
        
        // Auto-layout for the stack view
        verticalStackView.heightAnchor.constraint(equalToConstant: heightOfStackView)
            .isActive = true
        
        verticalStackView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
            .isActive = true
        
        verticalStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
            .isActive = true
        
        // do not give width, let the content determine it
    }
    
    private func addCustomViewsToStackView()
    {
        for _ in 0 ..< numberOfCustomViews
        {
            let customView = CustomView()
            customView.translatesAutoresizingMaskIntoConstraints = false
            verticalStackView.addArrangedSubview(customView)
            
            // Set width constraint of custom view
            customView.widthAnchor.constraint(equalToConstant: widthOfCustomView)
                .isActive = true
            
            // Set height constraint of custom view
            customView.heightAnchor.constraint(equalToConstant: heightOfCustomView)
                .isActive = true
        }
    }
}

This is the end result with the UIImageView a square and made circular in a vertical stack view which I believe is what you wanted:

Vertical UIStackView Aspect Ration UIView Square UIImage Custom UIView

Shawn Frank
  • 4,381
  • 2
  • 19
  • 29