7

I have a few UIStackView that I add programmatically and I want them to have a other Axis when the app is in say Regular Width and Any Height.

It this even possible, like it is in the interface builder?

All I bump into on Google is willTransitionToTraitCollection, but not what I need.

To make it easier to understand what I need:

for i in numberOfItems {
    let stackView = UIStackView()
    stackView.append... // add views in this new stack view

    // here is where I need help:
    stackView.axis = horizontal
    stackView.addSomething... stackView.axis = vertical if regular width and any height.

    existingStackView.append.... stackView
}

Edit:

I found a other way to do, but I get some strange behaviour on iPhone 6+ when I rotate it around. Git repo: https://github.com/bjaskj/iOSStackViewConstraints

class MyStackView: UIStackView {
    override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)

        if traitCollection.horizontalSizeClass == UIUserInterfaceSizeClass.Regular {
            axis = UILayoutConstraintAxis.Horizontal
        } else {
            axis = UILayoutConstraintAxis.Vertical
        }
    }
}

ViewController:

@IBOutlet weak var mainStackView: UIStackView!

override func viewDidLoad() {
    super.viewDidLoad()
    addElement("Name", description: "Saint Petersburg")
    addElement("Native name", description: "Санкт-Петербург")
    addElement("Country", description: "Russia")
    addElement("Federal district", description: "Northwestern")
    addElement("Economic region", description: "Northwestern")
    addElement("Established", description: "May 27, 1703")
}

func addElement(title:String, description:String) {

    let labelTitle = UILabel()
    labelTitle.backgroundColor = UIColor.redColor()
    labelTitle.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
    labelTitle.text = title
    labelTitle.textColor = UIColor.whiteColor()

    let labelDescription = UILabel()
    labelDescription.backgroundColor = UIColor.blueColor()
    labelDescription.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)
    labelDescription.text = description
    labelDescription.textColor = UIColor.whiteColor()

    let stackHolder = MyStackView()
    stackHolder.axis = .Vertical
    stackHolder.distribution = .FillEqually

    stackHolder.addArrangedSubview(labelTitle)
    stackHolder.addArrangedSubview(labelDescription)
    stackHolder.spacing = 8

    mainStackView.addArrangedSubview(stackHolder)
}

What happens when I rotate iPhone 6+ is this: enter image description here

But what I expect and get if I start the app in rotated position: enter image description here

Bjarte
  • 2,167
  • 5
  • 27
  • 37
  • Did you try to change the axis? Btw. everything what is possible in IB can be done in code. Except for watchOS development. – dasdom Sep 17 '15 at 13:53
  • Changing the Axis that works yes, BUT what I'm looking for is when I create these `UIStackViews` that they have this added to it, not that I have to rely on the view controller events to get notified and then loop through my stacks to adapt. – Bjarte Sep 17 '15 at 18:20

1 Answers1

7

Update:

Ok, so it seems like you have two questions:

1) How do I add the appropriate stackview.axis depending on the size class when I add my stackviews to the scene:

for i in numberOFItems {
    let stackView = UIStackView()

    if view.traitCollection.verticalSizeClass == .Unspecified && view.traitCollection.horizontalSizeClass == .Regular {
        stackView.axis = .Vertical
    } else {
        stackView.axis = .Horizonal
    }

    stackView.addArrangedSubview(arrayOfViews[i])
}

2) How to make that stackview change from horizontal to vertical axis when the phone orientation is changed:

You'll nee to have a an array of stackviews that you've initialized. Then you'll need to step through the stackviews in the delegate method and change their orientation.

override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
    var axis

    if view.traitCollection.verticalSizeClass == .Compact {
        axis = UILayoutConstraintAxis.Horizontal
    } else {
        axis = UILayoutConstraintAxis.Vertical
    }

    for stackView in stackViewArray {
        stackView.axis = axis
    }
}

The view has a traitCollection that includes verticalSizeClass and horizontalSizeClass. These can have the values of .Compact, .Regular, and .Unspecified.

The method traitCollectionDidChange should tell you whenever a size class is modified (i.e. when the phone is turned).

If this still does not answer your question, please try rewriting your question so it's easier to understand

Also, there is no way that I am aware of to set these properties once and be done with it, you have to take care of both cases.

Rob Norback
  • 6,401
  • 2
  • 34
  • 38
  • I'm not sure if you understood me correctly, is it possible to do this in my for loop, instead of making this on the UIViewController/UIView then doing a for loop over my subviews? Or making a custom class that inherits UIStackView and override it for each type of situation I could need. How does Interface builder do this? Do they add some magic code that sets this up via traitCollectionDidChange on the UIViewController or UIView when you hook it up in storyboard or XIB? – Bjarte Sep 18 '15 at 06:49
  • Hi @Bjarte, I updated my answer. There are simply some global variables that you can check against that tell you the size class. Cheers! – Rob Norback Sep 22 '15 at 12:53
  • So how would this change the axis when I rotate the device in the code that I posted under "// here is where I need help:" ? I want to do the add operation once. – Bjarte Sep 22 '15 at 13:54
  • I found some other way of doing it, but it almost solves it. It just misbehaves on iPhone 6+. – Bjarte Sep 28 '15 at 10:56
  • does it have the two columns in portrait? – Rob Norback Sep 28 '15 at 15:09
  • on iPhone 6+ and iPads yes. – Bjarte Sep 29 '15 at 06:40
  • Why do you check `== .Compact` and not wether vertical or horizontal the device orientation? – János Mar 20 '18 at 16:12