Rashad.Z
Rashad.Z

Reputation: 2604

UIView Setting Constraints Programmatically

I am kind of new to iOS and don't yet understand Constraints quite well. I am adding a set of dynamic views to my view controller which by default contains a scrollview and a container view on top. Everything is working fine and I was managing to add them below each other using the following:

TheView.frame = CGRectMake(5, CGFloat(position), self.view.frame.size.width-10, 40); //position is incremented so that they are below each other

But when I turn the phone to landscape, the views do not take the width of the main view so I added the following to the views:

TheView.translatesAutoresizingMaskIntoConstraints = false;
    let margins = contentView.layoutMarginsGuide // contentView is the container view
    TheView.leadingAnchor.constraintEqualToAnchor(margins.leadingAnchor).active = true
    TheView.trailingAnchor.constraintEqualToAnchor(margins.trailingAnchor).active = true

This made the views dynamically change their width when I rotate the device but they are now overlapping and I can't seem to find out how can I set them to be placed below each other like how they were.

UPDATE:

I removed the scrollview and everything from storyboard and added a scrollview and stack view programatically.

in viewdidload:

ScrollView = UIScrollView()
        ScrollView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(ScrollView)

        view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[scrollView]|", options: .AlignAllCenterX, metrics: nil, views: ["scrollView": ScrollView]))
        view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[scrollView]|", options: .AlignAllCenterX, metrics: nil, views: ["scrollView": ScrollView]))


        stackView = UIStackView()
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.distribution  = UIStackViewDistribution.EqualSpacing
        stackView.spacing   = 26.0
        stackView.axis = .Vertical
        ScrollView.addSubview(stackView)


        ScrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[stackView]|", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: ["stackView": stackView]))
        ScrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[stackView]|", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: ["stackView": stackView]))

adding the dynamic views:

for loop...

let Description = UILabel()
stackView.addArrangedSubview(Description)

let Value = UITextField()
stackView.addArrangedSubview(Value)

the views are added successful as before and there is scrolling. also the views are filling the stack view (width) but still not in landscape.

Upvotes: 0

Views: 640

Answers (1)

Vinzzz
Vinzzz

Reputation: 11724

You cannot at the same time:

  • define a frame for your views
  • define a set of constraints for these views

You do either one or the other.

You seem to be using iOS 9 APIs constraintEqualToAnchor , so you could as well put the 2 views you want to stack into a UIStackView, this would certainly be the simplest solution.

If you needed to support older versions of iOS (7, 8), this only mean you didn't defined enough constraints to place your views. TheView.leadingAnchor.constraintEqualToAnchor(margins.leadingAnchor) => this one places TheView left side (well, 'leading', as it can depend on the direction of the language displayed - e.g. it would be right for arabic) TheView.trailingAnchor.constraintEqualToAnchor(margins.trailingAnchor) constraints the other side.

You have 2 horizontal constraints, so what you miss are 2 other constraints, for vertical axis.

One of these constraints might be topAnchor or bottomAnchor (depending on where is TheView - By the way, UpperCase for instance variables is quite uncommon :)

The other constraint might be defined between TheView and the other subview, something like

let viewTop = NSLayoutConstraint(item: TheView, attribute: .Top, relatedBy: .Equal, toItem: scrollView, attribute: .Bottom, multiplier: 1, constant: 0) , if you want to place TheView below scrollView

Beware that UIScrollView behave a little differently with Auto-layout. You have to give it one set of constraints with views outside its hierarchy (to constraint the scrollview bounds) and you can use another set of constraints to place the scrollView's subviews (and this way, constraint its contentSize) (see Apple Technical Note on how to layout UIScrollView with constraints

Upvotes: 3

Related Questions