Home > Back-end >  How can I programmatically adjust the size of member views of a UIStackView?
How can I programmatically adjust the size of member views of a UIStackView?

Time:04-07

Scenario: I have created a vertical UIStackView containing rows of elements.
One row contains duplicate square UIViews (Address1 & Address2) whose size I want to adjust.

Note: I'm not using Interface Builder. Only via code.

Problem: The two squares appear to be fixed rectangles that I can't 'square' to an appropriate size.

Remedy?

Here's the code:

class MainView: UIView {
    @available(*, unavailable)
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // ------------------------------------------------
    
    @objc func onLeftAddressTap() {
        print("Left Address Selected")
        leftLabel.isHidden = false
        rightLabel.isHidden = !leftLabel.isHidden
        leftContainerView.layer.borderColor = UIColor.green.cgColor
        rightContainerView.layer.borderColor = UIColor.lightGray.cgColor
    }
    
    @objc func onRightAddressTap() {
        print("Right Address Selected")
        leftLabel.isHidden = true
        rightLabel.isHidden = !leftLabel.isHidden
        rightContainerView.layer.borderColor = UIColor.green.cgColor
        leftContainerView.layer.borderColor = UIColor.lightGray.cgColor
    }

    // ------------------------------------------------
    
    let leftLabel = UILabel()
    let rightLabel = UILabel()
    
    let leftContainerView: UIView = {
        let view = UIView(frame: CGRect())
        view.layer.borderWidth = 1.0
        view.layer.borderColor = UIColor.green.cgColor
        return view
    }()
    
    let rightContainerView: UIView = {
        let view = UIView(frame: CGRect())
        view.layer.borderWidth = 1.0
        view.layer.borderColor = UIColor.lightGray.cgColor
        return view
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = .white
        setupViews()
    }

    // ------------------------------------------------
    
    fileprivate func setupAddressStack() -> UIStackView {
        setupLeftAddress()
        setupRightAddress()

        // ------------------------------------------------
        // Address StackView:
        
        let addressStackView = UIStackView(arrangedSubviews: [leftContainerView, rightContainerView])
        addressStackView.axis = .horizontal
        addressStackView.spacing = 10
        addressStackView.distribution = .fillEqually
        addressStackView.alignment = .fill
    
        return addressStackView
    }
    
    // ------------------------------------------------
    
    fileprivate func setupViews() {
        // Image Logol
        let ratImageview = UIImageView(image: UIImage(named: "Rat"))
        ratImageview.frame = CGRect(x: 0, y: 0, width: 68, height: 68)
        
        // TitleLabel
        let titleLabel = UILabel(frame: CGRect())
        let titleString = "Where should we send your card?  We'll cancel it and send you a new one."
        titleLabel.text = titleString
        titleLabel.textAlignment = .center
        titleLabel.font = .systemFont(ofSize: 12)
        titleLabel.lineBreakMode = .byWordWrapping
        titleLabel.numberOfLines = 0
    
        // Status Label:
        let statusLabel = UILabel(frame: CGRect())
        let statusString = "Your existing card ending in 0492 will be cancelled and yournew card shoud arrive withi 6 business days via USPS."
        statusLabel.text = statusString
        statusLabel.textAlignment = .center
        statusLabel.font = .systemFont(ofSize: 12)
        statusLabel.lineBreakMode = .byWordWrapping
        statusLabel.numberOfLines = 0
        
        // ------------------------------------------------
        // Container SackView:
        let ContainerStackView = UIStackView(arrangedSubviews: [titleLabel, setupAddressStack(), statusLabel])
        ContainerStackView.axis = .vertical
        ContainerStackView.distribution = .fillEqually
        ContainerStackView.spacing = 20

        // Logo:
        addSubview(ratImageview)
        ratImageview.translatesAutoresizingMaskIntoConstraints = false
        ratImageview.centerXAnchor.constraint(equalTo: centerXAnchor, constant: 0).isActive = true
        ratImageview.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 10).isActive = true
        
        // StackView:
        addSubview(ContainerStackView)
        
        ContainerStackView.translatesAutoresizingMaskIntoConstraints = false
        ContainerStackView.leftAnchor.constraint(equalTo: leftAnchor, constant: 10).isActive = true
        ContainerStackView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 75).isActive = true
        ContainerStackView.rightAnchor.constraint(equalTo: rightAnchor, constant: -10).isActive = true
        ContainerStackView.bottomAnchor.constraint(equalTo: centerYAnchor, constant: 0).isActive = true
    }
}

// ==============================================================================================

private extension MainView {
    func setupLeftAddress() {
        // LeftLabel:
        leftLabel.numberOfLines = 0
        leftLabel.text = "Mother had a feeling, I might be too appealing."
        leftLabel.font = UIFont.systemFont(ofSize: 9)
        leftLabel.adjustsFontSizeToFitWidth = true
        leftLabel.isHidden = false
        
        leftContainerView.addSubview(leftLabel)
        
        leftLabel.translatesAutoresizingMaskIntoConstraints = false
        leftLabel.leftAnchor.constraint(equalTo: leftContainerView.leftAnchor, constant: 10).isActive = true
        leftLabel.rightAnchor.constraint(equalTo: leftContainerView.rightAnchor, constant: -10).isActive = true
        leftLabel.centerYAnchor.constraint(equalTo: leftContainerView.centerYAnchor).isActive = true
        
        let leftButton = UIButton()
        leftButton.addTarget(self, action: #selector(onLeftAddressTap), for: .touchUpInside)
        
        leftContainerView.addSubview(leftButton)
        
        leftButton.translatesAutoresizingMaskIntoConstraints = false
        leftButton.leftAnchor.constraint(equalTo: leftContainerView.leftAnchor).isActive = true
        leftButton.rightAnchor.constraint(equalTo: leftContainerView.rightAnchor).isActive = true
        leftButton.topAnchor.constraint(equalTo: leftContainerView.topAnchor).isActive = true
        leftButton.bottomAnchor.constraint(equalTo: leftContainerView.bottomAnchor).isActive = true
    }
    
    func setupRightAddress() {
        rightLabel.numberOfLines = 0
        rightLabel.text = "This is the right label."
        rightLabel.font = UIFont.systemFont(ofSize: 9)
        rightLabel.adjustsFontSizeToFitWidth = true
        rightLabel.isHidden = true
        
        rightContainerView.addSubview(rightLabel)
        
        rightLabel.translatesAutoresizingMaskIntoConstraints = false
        rightLabel.leftAnchor.constraint(equalTo: rightContainerView.leftAnchor, constant: 10).isActive = true
        rightLabel.rightAnchor.constraint(equalTo: rightContainerView.rightAnchor, constant: -10).isActive = true
        rightLabel.centerYAnchor.constraint(equalTo: rightContainerView.centerYAnchor).isActive = true
        
        let rightButton = UIButton()
        rightButton.addTarget(self, action: #selector(onRightAddressTap), for: .touchUpInside)
        rightContainerView.addSubview(rightButton)
        rightButton.translatesAutoresizingMaskIntoConstraints = false
        
        rightButton.leftAnchor.constraint(equalTo: rightContainerView.leftAnchor).isActive = true
        rightButton.rightAnchor.constraint(equalTo: rightContainerView.rightAnchor).isActive = true
        rightButton.topAnchor.constraint(equalTo: rightContainerView.topAnchor).isActive = true
        rightButton.bottomAnchor.constraint(equalTo: rightContainerView.bottomAnchor).isActive = true
    }
}

enter image description here

CodePudding user response:

If you want the "address containers" to be square - 1:1 ratio...

Add this line in setupLeftAddress():

leftContainerView.heightAnchor.constraint(equalTo: leftContainerView.widthAnchor).isActive = true

Add this line in setupRightAddress():

rightContainerView.heightAnchor.constraint(equalTo: rightContainerView.widthAnchor).isActive = true

and change your stack view distribution in setupViews():

//ContainerStackView.distribution = .fillEqually
ContainerStackView.distribution = .fill

That changes this:

enter image description here

to this:

enter image description here

  • Related