Create a Horizontal Stackview with 2 UiView Inside

10,536

Couple notes...

First, you'll be better off using auto-layout and constraints (as opposed to explicit frames), particularly with stack views.

Second, UIStackView properties are probably a little different than what you're thinking...

For a horizontal stack view,

  • alignment controls the vertical alignment of the arranged subviews
  • distribution controls how the subviews fill the stack view horizontally

For a vertical stack view,

  • alignment controls the horizontal alignment of the arranged subviews
  • distribution controls how the subviews fill the stack view vertically

I'm assuming this is what you're going for:

enter image description here

enter image description here

Here is the code used to create that (lots of comments, should get you on your way):

class SampleViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let mStackView = UIStackView()

        // horizontal stack view
        mStackView.axis  = .horizontal

        // distribution  = fillEqually ... means make each arranged subview equal width
        mStackView.distribution  = .fillEqually

        // alignment = center ... means center the arranged subviews vertically
        mStackView.alignment = .center

        // spacing = 10 ... horizontal gap between arranged subviews
        mStackView.spacing = 10

        // create the left-side "Donate" view
        let donateView = createMyView("Donate", bgColor: UIColor.green, txtColor: UIColor.black)

        // create the right-side "Receive" view
        let receiveView = createMyView("Receive", bgColor: UIColor.yellow, txtColor: UIColor.blue)

        mStackView.addArrangedSubview(donateView)
        mStackView.addArrangedSubview(receiveView)

        // using auto-layout
        mStackView.translatesAutoresizingMaskIntoConstraints = false

        view.addSubview(mStackView)

        // setup constraints for mStackView
        // we'll make it the width of the view, and centered vertically
        // allow the height of the donate and receive views to determine the height of the stack view, so
        //      no bottom or height constraint
        NSLayoutConstraint.activate([

            mStackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 0.0),
            mStackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 0.0),
            mStackView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0.0),

            ])


    }

    func createMyView(_ imageName: String, bgColor: UIColor, txtColor: UIColor) -> UIView {

        let myView = UIView()
        myView.backgroundColor = bgColor

        let vStackView = UIStackView()

        // vertical stack view
        vStackView.axis  = .vertical

        // alignment = center ... means the arranged subviews will be centered horizontally
        vStackView.alignment = .center

        // distribution = fill ... means the arranged subviews will fill the height of the stack view
        vStackView.distribution  = .fill

        // spacing = 1 ... vertical gap between arranged subviews
        vStackView.spacing = 1

        let vImageName = imageName

        let vImageView = UIImageView()

        if let vImage = UIImage(named: vImageName) {
            vImageView.image = vImage
        }

        let vLabel = UILabel()

        vLabel.text = imageName
        vLabel.textColor = txtColor
        vLabel.textAlignment = .center
        vLabel.font = vLabel.font.withSize(14)
        vLabel.backgroundColor = UIColor(white: 0.9, alpha: 1.0)

        // add the stack view to myView
        myView.addSubview(vStackView)

        // add the image view and label as arranged subviews of the stack view
        vStackView.addArrangedSubview(vImageView)
        vStackView.addArrangedSubview(vLabel)

        // we're going to use auto-layout
        myView.translatesAutoresizingMaskIntoConstraints = false
        vStackView.translatesAutoresizingMaskIntoConstraints = false
        vImageView.translatesAutoresizingMaskIntoConstraints = false
        vLabel.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([

            // add width and height constraints for the image view
            vImageView.widthAnchor.constraint(equalToConstant: 100.0),
            vImageView.heightAnchor.constraint(equalToConstant: 200.0),

            // constrain the stack view to all four side of myView
            vStackView.topAnchor.constraint(equalTo: myView.topAnchor, constant: 0.0),
            vStackView.bottomAnchor.constraint(equalTo: myView.bottomAnchor, constant: 0.0),
            vStackView.leadingAnchor.constraint(equalTo: myView.leadingAnchor, constant: 0.0),
            vStackView.trailingAnchor.constraint(equalTo: myView.trailingAnchor, constant: 0.0),

            ])

        return myView

    }

}
Share:
10,536
A.s.ALI
Author by

A.s.ALI

Updated on June 09, 2022

Comments

  • A.s.ALI
    A.s.ALI almost 2 years

    What I Want:

    I want to place 2 Views side by side in a horizontal way. For this I am creating UIStackView programmatically. Look at the below snippet

    What I Have Done:

    let mStackView = UIStackView()
    mStackView.axis  = UILayoutConstraintAxis.horizontal
    mStackView.distribution  = UIStackViewDistribution.fillEqually
    mStackView.alignment = UIStackViewAlignment.center
    mStackView.spacing = 10
    

    Now inside this I want to put 2 UIView. Each UIView will keep center aligned UIImage and UILabel. For this I am using another UIStackView in each UIView

    have a look at this snippet.

    let mDonationView = UIView()
    mDonationView.backgroundColor = UIColor.green
    
    let SV = UIStackView()
    SV.axis  = UILayoutConstraintAxis.vertical
    SV.distribution  = UIStackViewDistribution.fill
    SV.alignment = UIStackViewAlignment.leading
    SV.spacing = 1
    SV.alignment = .top
    
    let imageName = "Donate"
    let image = UIImage(named: imageName)
    let imageView = UIImageView(image: image!)
    imageView.frame = CGRect(x: 0, y: 0, width: 100, height: 200)
    
    let lbl = UILabel(frame: CGRect(x: 0, y: 0, width: 150, height: 21))
    lbl.text = "Donate"
    lbl.textColor = UIColor(hex:AppColor.colorTextPrimary)
    lbl.font = lbl.font.withSize(14)
    
    SV.addArrangedSubview(imageView)
    SV.addArrangedSubview(lbl)
    SV.translatesAutoresizingMaskIntoConstraints = false
    
    mDonationView.addSubview(SV)
    

    and in the end I am adding this back to main UIStackView namely mStackView in first code snippet. See below:

    mStackView.addArrangedSubview(mDonationView)
    

    similarly I am creating another view and adding in above shown way.

    Problem:

    1. My problem is I can see 2 views side by side, but in that the UIImageView and UILabel are aligned on left where I wanted to be center horizontally and Vertically inside UIView.
    2. Both UIView must be equal in width
    3. UIView are not taking colors which I have given green to each UIView