iosswiftuiimagenslayoutconstraint

setup all of the properties of the stack view


I'm using an SF symbol image into a UIImageView. I have given the constrains as well. What I have seen running the same code into different simulators actually increases the width of the image but I want to give fixed width into different iOS simulators.

Here is the code for the image:

let rightImageView: UIImageView = {
    let rightImageView = UIImageView()
    rightImageView.image = UIImage(systemName: "arrow.right")
    rightImageView.translatesAutoresizingMaskIntoConstraints = false
    rightImageView.tintColor = .purple
    return rightImageView
}()

Here is the constrains for it and other properties:

private func setUpUI() {
    view.addSubview(stackview)
    stackview.dm_addArrangedSubviews(titleLable)
    stackview.dm_addArrangedSubviews(viewAllLable)
    stackview.dm_addArrangedSubviews(rightImageView)
    view.addSubview(collectionView)
    
    let safeArea = view.safeAreaLayoutGuide
    NSLayoutConstraint.activate([
        
        stackview.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            stackview.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            stackview.topAnchor.constraint(equalTo: view.topAnchor),
            collectionView.topAnchor.constraint(equalTo: stackview.bottomAnchor),
            collectionView.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor),
            collectionView.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor),
            collectionView.heightAnchor.constraint(equalToConstant: view.frame.width/2)
    ])
}

Here is the screenshot in iPhone 15 Pro Max: 15th Pro max

Here is the screenshot in iPhone 15 simulator: 15

Here is the screenshot on different mode, the right arrow image width is set properly: different mode

As you can see, the width of the rightImageView property is increased. How can I give fixed width for different device?


Solution

  • Set the rightImageView.widthAnchor equal to the rightImageView.heightAnchor.

    Set content hugging priority on viewAllLable so it doesn't stretch horizontally.

    Quick example:

    class ViewController: UIViewController {
        
        let rightImageView: UIImageView = {
            let rightImageView = UIImageView()
            rightImageView.image = UIImage(systemName: "arrow.right")
            rightImageView.tintColor = .purple
            return rightImageView
        }()
        
        let stackview: UIStackView = {
            let v = UIStackView()
            v.translatesAutoresizingMaskIntoConstraints = false
            v.spacing = 8
            return v
        }()
        
        let titleLable: UILabel = {
            let v = UILabel()
            v.font = .systemFont(ofSize: 24.0, weight: .regular)
            v.text = "Similar Movies"
            return v
        }()
    
        let viewAllLable: UILabel = {
            let v = UILabel()
            v.font = .systemFont(ofSize: 24.0, weight: .regular)
            v.text = "View all"
            return v
        }()
        
        override func viewDidLoad() {
            super.viewDidLoad()
            setUpUI()
        }
        
        private func setUpUI() {
            view.addSubview(stackview)
            stackview.addArrangedSubview(titleLable)
            stackview.addArrangedSubview(viewAllLable)
            stackview.addArrangedSubview(rightImageView)
            
            let safeArea = view.safeAreaLayoutGuide
            NSLayoutConstraint.activate([
                
                // constrain to safeArea, with 8-point "padding" on top/leading/trailing
                stackview.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor, constant: 8.0),
                stackview.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor, constant: -8.0),
                stackview.topAnchor.constraint(equalTo: safeArea.topAnchor, constant: 8.0),
                
                rightImageView.widthAnchor.constraint(equalTo: rightImageView.heightAnchor),
                
            ])
            
            // don't let viewAllLable stretch horizontally
            viewAllLable.setContentHuggingPriority(.required, for: .horizontal)
            
        }
        
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            // toggle colors so we can see the framing
            if titleLable.backgroundColor == .yellow {
                titleLable.backgroundColor = .clear
                viewAllLable.backgroundColor = .clear
                rightImageView.backgroundColor = .clear
                
                stackview.layer.borderWidth = 0
            } else {
                titleLable.backgroundColor = .yellow
                viewAllLable.backgroundColor = .green
                rightImageView.backgroundColor = .cyan
                
                stackview.layer.borderColor = UIColor.red.cgColor
                stackview.layer.borderWidth = 1
            }
        }
    }
    

    Looks like this:

    enter image description here

    and element widths stay the same, regardless of view width:

    enter image description here

    When you run the above code, tap anywhere to toggle the colors on/off so you can see the framing:

    enter image description here

    enter image description here