Add Views in Uistackview Programmatically

Add views in UIStackView programmatically

Stack views use intrinsic content size, so use layout constraints to define the dimensions of the views.

There is an easy way to add constraints quickly (example):

[view1.heightAnchor constraintEqualToConstant:100].active = true;

Complete Code:

- (void) setup {

//View 1
UIView *view1 = [[UIView alloc] init];
view1.backgroundColor = [UIColor blueColor];
[view1.heightAnchor constraintEqualToConstant:100].active = true;
[view1.widthAnchor constraintEqualToConstant:120].active = true;


//View 2
UIView *view2 = [[UIView alloc] init];
view2.backgroundColor = [UIColor greenColor];
[view2.heightAnchor constraintEqualToConstant:100].active = true;
[view2.widthAnchor constraintEqualToConstant:70].active = true;

//View 3
UIView *view3 = [[UIView alloc] init];
view3.backgroundColor = [UIColor magentaColor];
[view3.heightAnchor constraintEqualToConstant:100].active = true;
[view3.widthAnchor constraintEqualToConstant:180].active = true;

//Stack View
UIStackView *stackView = [[UIStackView alloc] init];

stackView.axis = UILayoutConstraintAxisVertical;
stackView.distribution = UIStackViewDistributionEqualSpacing;
stackView.alignment = UIStackViewAlignmentCenter;
stackView.spacing = 30;


[stackView addArrangedSubview:view1];
[stackView addArrangedSubview:view2];
[stackView addArrangedSubview:view3];

stackView.translatesAutoresizingMaskIntoConstraints = false;
[self.view addSubview:stackView];


//Layout for Stack View
[stackView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = true;
[stackView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor].active = true;
}

Note: This was tested on iOS 9

UIStackView Equal Spacing (centered)

Adding views dynamically to UIStackview

It may help you. Please follow this points:

  • Add UIScrollView to your UIViewController in storyboard or XIB.
  • Initiate an NSMutableArray name it arrViews gets server response and adds view in the array.
  • Initialise UIStackViewpass arrView array in the init method.
  • After that UIStackView will be added subview of UIScrollView.
  • Add constraint programmatically to UIStackView. That's it.

    if let response = self.serverResponse {
    if let body = response.responseBody {

    if let view = body.views {
    arrViews = createSubViews(view)
    }

    }
    }

    let stackView = UIStackView(arrangedSubviews: arrViews)
    stackView.translatesAutoresizingMaskIntoConstraints = false
    stackView.axis = .vertical
    stackView.spacing = 16
    stackView.distribution = .fill
    self.scrollView.addSubview(stackView)

    //constraints

    let leading = NSLayoutConstraint(item: stackView, attribute: .leading, relatedBy: .equal, toItem: self.scrollView, attribute: .leading, multiplier: 1.0, constant: 0)
    self.scrollView.addConstraint(leading)
    let trailing = NSLayoutConstraint(item: stackView, attribute: .trailing, relatedBy: .equal, toItem: self.scrollView, attribute: .trailing, multiplier: 1.0, constant: 0)
    self.scrollView.addConstraint(trailing)
    let top = NSLayoutConstraint(item: stackView, attribute: .top, relatedBy: .equal, toItem: self.scrollView, attribute: .top, multiplier: 1.0, constant: 0)
    self.scrollView.addConstraint(top)

    let bottom = NSLayoutConstraint(item: stackView, attribute: .bottom, relatedBy: .equal, toItem: self.scrollView, attribute: .bottom, multiplier: 1.0, constant: 0)
    self.scrollView.addConstraint(bottom)

    let equalWidth = NSLayoutConstraint(item: stackView, attribute: .width, relatedBy: .equal, toItem: self.scrollView, attribute: .width, multiplier: 1.0, constant: 0)

    self.scrollView.addConstraint(equalWidth)


    leading.isActive = true
    trailing.isActive = true
    top.isActive = true
    bottom.isActive = true
    equalWidth.isActive = true

Hope it will help you. Happy coding :)

Programmatically adding views to a UIStackView

Two problems,

stackedInfoView.centerXAnchor.constraint(equalTo:self.extendedNavView.centerXAnchor).isActive = true
stackedInfoView.centerYAnchor.constraint(equalTo:self.extendedNavView.centerYAnchor).isActive = true

should be put after self.extendedNavView.addSubview(stackedInfoView). Because the stack view must be in the view hierarchy before configure the constraints.

Second, add stackedInfoView.translatesAutoresizingMaskIntoConstraints = false to tell UIKit you want to use auto layout to set the position of the stack view.

The following code should work if extendedNavView has no layout issue in the storyboard:

override func viewDidLoad() {
super.viewDidLoad()

var nameLabel: UILabel!
var ageLabel: UILabel!

var stackedInfoView: UIStackView!

nameLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 120.0, height: 24.0))
ageLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 80.0, height: 24.0))
nameLabel.text = "Harry Potter"
ageLabel.text = "100"

stackedInfoView = UIStackView(arrangedSubviews: [nameLabel, ageLabel])
stackedInfoView.axis = .horizontal
stackedInfoView.distribution = .equalSpacing
stackedInfoView.alignment = .center
stackedInfoView.spacing = 30.0

stackedInfoView.translatesAutoresizingMaskIntoConstraints = false

self.extendedNavView.addSubview(stackedInfoView) //extendedNavView is configured inside Storyboard

stackedInfoView.centerXAnchor.constraint(equalTo: self.extendedNavView.centerXAnchor).isActive = true
stackedInfoView.centerYAnchor.constraint(equalTo: self.extendedNavView.centerYAnchor).isActive = true

}

Adding labels and textviews in a stack view programmatically in swift

UILabel & UITextView are both UIKit classes written in Objective-C. They are reference types, NOT value types.

When you write following -

let label1 = label
let label2 = label

let t1 = textView
let t2 = textView

Both label1 & label2 are pointing to the one & same instance of UILabel. So is the case for t1 & t2 as well.

When you add them like this -

//Add StackView + elements
stackHTS.addArrangedSubview(label1)
stackHTS.addArrangedSubview(t1)
stackHTS.addArrangedSubview(label2)
stackHTS.addArrangedSubview(t2)

You expect 2 labels and 2 textViews to be added to the StackView. You are adding only 1 label and 1 textView though.

You expect to see all of following -

        label1.text = "Title1:"
label2.text = "title2:"

t1.text = """
1. On your profile tap menu
2. Tap settings
3. Tap accounts
4. Tap set up professional account
"""

t2.text = """
1. On your profile tap "Edit profile"
2. Link your created page to your account
"""

However you are only seeing following -

        label2.text = "title2:"

t2.text = """
1. On your profile tap "Edit profile"
2. Link your created page to your account
"""

Solutions -

  1. Create two separate instances of UITextView & UILabel like you have already done for the first two and Add these new instances to stack view as well.
  2. Use one UILabel and remove everything else. Use NSAttributedString API to stylize your text as you want for different sections / paragraphs and assign it to UILabel.attributedText.

Elements not adding to UIStackView , programmatically?

Make main stackView to align bottom

You can try to adding a height for mainStack subviews like

v.translatesAutoresizingMaskIntoConstraints = false
v.heightAnchor.constraint(equalToConstant: 150).isActive = true

in

func builStartingArray(){
let viewStick:UIView = {
let v = UIView()
v.backgroundColor = .red
v.translatesAutoresizingMaskIntoConstraints = false
v.heightAnchor.constraint(equalToConstant: 150).isActive = true
return v
}()
let viewStick2:UIView = {
let v = UIView()
v.backgroundColor = .red
v.translatesAutoresizingMaskIntoConstraints = false
v.heightAnchor.constraint(equalToConstant: 150).isActive = true
return v
}()
mainStackView.addArrangedSubview(viewStick)
mainStackView.addArrangedSubview(viewStick2)
}

All code

import UIKit

class ViewController:UIViewController{

let stackView:UIStackView = {
let st = UIStackView()
st.axis = .horizontal
st.alignment = .center
st.distribution = .fill
// st.backgroundColor = .cyan
st.layer.shadowColor = UIColor.gray.cgColor
st.layer.shadowOffset = .zero
st.layer.shadowRadius = 5
st.layer.shadowOpacity = 1
st.spacing = 10
st.translatesAutoresizingMaskIntoConstraints = false

return st
}()
let generateButton:UIButton = {
let btn = UIButton()
btn.setTitle("Generate Array", for: .normal)
btn.backgroundColor = UIColor(red: 0.92, green: 0.30, blue: 0.29, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let BubbleSort:UIButton = {
let btn = UIButton()
btn.setTitle("BubbleSort", for: .normal)
btn.backgroundColor = UIColor(red: 0.41, green: 0.43, blue: 0.88, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let MergeSort:UIButton = {
let btn = UIButton()
btn.setTitle("MergeSort", for: .normal)
btn.backgroundColor = UIColor(red: 0.10, green: 0.16, blue: 0.34, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let InsertionSort:UIButton = {
let btn = UIButton()
btn.setTitle("InsertionSort", for: .normal)
btn.backgroundColor = UIColor(red: 0.19, green: 0.22, blue: 0.32, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let SelectionSort:UIButton = {
let btn = UIButton()
btn.setTitle("SelectionSort", for: .normal)
btn.backgroundColor = UIColor(red: 0.51, green: 0.20, blue: 0.44, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let mainStackView:UIStackView = {
let st = UIStackView()
st.backgroundColor = .gray
st.axis = .horizontal
st.distribution = .fillEqually
st.alignment = .top
st.spacing = 1
st.translatesAutoresizingMaskIntoConstraints = false
return st
}()
let baseView:UIView = {
let vw = UIView()
vw.backgroundColor = UIColor(red: 0.07, green: 0.54, blue: 0.65, alpha: 1.00)
vw.translatesAutoresizingMaskIntoConstraints = false
vw.layer.cornerRadius = 3
vw.layer.masksToBounds = true
return vw
}()
public override func viewDidLoad() {
view.addSubview(mainStackView)
view.addSubview(stackView)
view.addSubview(baseView)
edgesForExtendedLayout = []
stackView.addArrangedSubview(generateButton)
stackView.addArrangedSubview(BubbleSort)
stackView.addArrangedSubview(MergeSort)
stackView.addArrangedSubview(InsertionSort)
stackView.addArrangedSubview(SelectionSort)

stackView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
stackView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
stackView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
stackView.heightAnchor.constraint(equalToConstant: 50).isActive = true

baseView.bottomAnchor.constraint(equalTo: view.bottomAnchor,constant: -2).isActive = true
baseView.leftAnchor.constraint(equalTo: view.leftAnchor,constant: 5).isActive = true
baseView.rightAnchor.constraint(equalTo: view.rightAnchor,constant: -5).isActive = true
baseView.heightAnchor.constraint(equalToConstant: 15).isActive = true

mainStackView.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 5).isActive = true
mainStackView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 5).isActive = true
mainStackView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -5).isActive = true
mainStackView.bottomAnchor.constraint(equalTo: baseView.topAnchor, constant: -5).isActive = true

builStartingArray()

}

func builStartingArray(){
let viewStick:UIView = {
let v = UIView()
v.backgroundColor = .red
v.translatesAutoresizingMaskIntoConstraints = false
v.heightAnchor.constraint(equalToConstant: 150).isActive = true
return v
}()
let viewStick2:UIView = {
let v = UIView()
v.backgroundColor = .red
v.translatesAutoresizingMaskIntoConstraints = false
v.heightAnchor.constraint(equalToConstant: 150).isActive = true
return v
}()
mainStackView.addArrangedSubview(viewStick)
mainStackView.addArrangedSubview(viewStick2)
}
}

Sample Image

Stacking views programmatically in UIStackView

Couple things...

First, I'd suggest learning how constraints and auto-layout work before using something like SnapKit. It can make some things easier --- but until one has a good understanding of the fundamentals, it's not clear what's doing what.

Second, during development, it helps to give views and subviews contrasting background colors. Makes it much easier to see what's happening to the frames at run-time.

So, if you're going to stick with SnapKit...

Try to keep code "clean." That is, don't put anything inside a snp.makeConstraints block that isn't directly related (such as setting background colors).

In your ListingEntry class, you're adding a subview (containerView) and giving that view a width and height of 150, but you are not constraining it to its superview... which results in a view height of Zero.

Take a look at the modifications I made to your code. I added comments that should make the changes clear:

class MiscViewController: UIViewController {

var listingsView: ListingsView = {
let v = ListingsView()
return v
}()

override func viewDidLoad() {
super.viewDidLoad()

view.addSubview(listingsView)

listingsView.backgroundColor = .red

// constrain listingsView to all 4 sides with 40-pt "padding"
listingsView.snp.makeConstraints { (make) in
make.top.bottom.leading.trailing.equalToSuperview().inset(40.0)
}

let listings: [Listing] = [
Listing(id: "A"),
Listing(id: "B"),
Listing(id: "C"),
]

listingsView.setUpListings(listings: listings)

}

}

struct Listing {
var id: String = ""
}

class ListingsView : UIView {
var containerView: UIView!
var listingsContainerView: UIStackView!

init() {
super.init(frame: CGRect.zero)
// probably want to set clipsToBounds so any content doesn't extend outside the frame
clipsToBounds = true
setUpContainerView()
setUpListingsContainer()
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

func setUpContainerView() {
containerView = UIView()

self.addSubview(containerView)

containerView.backgroundColor = UIColor.green

// constrain containerView to all 4 sides
containerView.snp.makeConstraints { (make) in
make.top.bottom.leading.trailing.equalToSuperview()
}
}

func setUpListingsContainer() {
listingsContainerView = UIStackView()
listingsContainerView.distribution = .equalSpacing
listingsContainerView.alignment = .fill
listingsContainerView.axis = .vertical
listingsContainerView.spacing = 10

containerView.addSubview(listingsContainerView)

// constrain listingsContainerView (a stack view) to all 4 sides
listingsContainerView.snp.makeConstraints { (make) in
make.top.leading.bottom.trailing.equalToSuperview()
}
}

func setUpListings(listings: [Listing]) {
for listing in listings {
let listingEntry = ListingEntry(listingId: listing.id)
listingEntry.backgroundColor = .cyan
listingsContainerView.addArrangedSubview(listingEntry)
}
}

class ListingEntry : UIView {
var listingId: String?
var containerView: UIView!

init(listingId: String) {
super.init(frame: CGRect.zero)
self.listingId = listingId
self.setUpContainerView()
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

func setUpContainerView() {
containerView = UIView()
containerView.backgroundColor = .gray
self.addSubview(containerView)

containerView.snp.makeConstraints { (make) in
// you want the "listing container" to be 150 x 150 pts
make.width.equalTo(150)
make.height.equalTo(150)
// and it needs top and bottom constraints to give self a height value
make.top.bottom.equalToSuperview()
// and it needs an x-position constraint
make.leading.equalToSuperview()
}
}
}
}

I've set the "main" ListingsView background color to red ... you don't see it because its containerView subview is green and fills the view.

Each ListingEntry view has a cyan background color, and its containerView has a gray background color.

The result:

Sample Image

and Debug View Hierarchy:

Sample Image

Last notes...

  • You set your StackView .distribution = .equalSpacing but you also set .spacing = 10, which doesn't make sense.
  • If you have more ListingEntry views than will fit vertically, you'll run into problems. I'd expect you'd put that into a scroll view.

Proportionally set views inside UIStackView using multiplier - swift - programmatically

First add arranged subviews, then activate constraints related to stackView.

let view1 = UIView()
let view2 = UIView()
let view3 = UIView()

view1.backgroundColor = .red
view2.backgroundColor = .blue
view3.backgroundColor = .green

let stackView = UIStackView(arrangedSubviews: [view1, view2, view3])
stackView.frame = CGRect(x: 0, y: 0, width: 40, height: 100)
stackView.axis = .vertical

view1.heightAnchor.constraint(equalTo: stackView.heightAnchor, multiplier: 0.2).isActive = true
view2.heightAnchor.constraint(equalTo: stackView.heightAnchor, multiplier: 0.6).isActive = true
view3.heightAnchor.constraint(equalTo: stackView.heightAnchor, multiplier: 0.2).isActive = true

Sample Image



Related Topics



Leave a reply



Submit