I'm trying to figure this out since last week without going any step further. Ok, so I need to apply some constraints programmatically in Swift to a UIView using this code:
var new_view:UIView! = UIView(frame: CGRectMake(0, 0, 100, 100));
new_view.backgroundColor = UIColor.redColor();
view.addSubview(new_view);
var constX:NSLayoutConstraint = NSLayoutConstraint(item: new_view, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0);
self.view.addConstraint(constX);
var constY:NSLayoutConstraint = NSLayoutConstraint(item: new_view, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0);
self.view.addConstraint(constY);
var constW:NSLayoutConstraint = NSLayoutConstraint(item: new_view, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: new_view, attribute: NSLayoutAttribute.Width, multiplier: 1, constant: 0);
self.view.addConstraint(constW);
var constH:NSLayoutConstraint = NSLayoutConstraint(item: new_view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: new_view, attribute: NSLayoutAttribute.Height, multiplier: 1, constant: 0);
self.view.addConstraint(constH);
But Xcode returns this weird output:
2014-10-03 09:48:12.657 Test[35088:2454916] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x7fa4ea446830 UIView:0x7fa4ea429290.centerX == UIView:0x7fa4ea4470f0.centerX>",
"<NSAutoresizingMaskLayoutConstraint:0x7fa4ea4516c0 h=--& v=--& UIView:0x7fa4ea429290.midX == + 50>",
"<NSLayoutConstraint:0x7fa4ea452830 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7fa4ea4470f0(375)]>",
"<NSAutoresizingMaskLayoutConstraint:0x7fa4ea446db0 h=-&- v=-&- 'UIView-Encapsulated-Layout-Left' H:|-(0)-[UIView:0x7fa4ea4470f0] (Names: '|':UIWindow:0x7fa4ea444b20 )>"
)
Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7fa4ea446830 UIView:0x7fa4ea429290.centerX == UIView:0x7fa4ea4470f0.centerX>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in
<UIKit/UIView.h> may also be helpful.
2014-10-03 09:48:12.658 Test[35088:2454916] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x7fa4ea44d160 UIView:0x7fa4ea429290.centerY == UIView:0x7fa4ea4470f0.centerY>",
"<NSAutoresizingMaskLayoutConstraint:0x7fa4ea451b30 h=--& v=--& UIView:0x7fa4ea429290.midY == + 50>",
"<NSLayoutConstraint:0x7fa4ea44cf00 'UIView-Encapsulated-Layout-Height' V:[UIView:0x7fa4ea4470f0(667)]>",
"<NSAutoresizingMaskLayoutConstraint:0x7fa4ea452700 h=-&- v=-&- 'UIView-Encapsulated-Layout-Top' V:|-(0)-[UIView:0x7fa4ea4470f0] (Names: '|':UIWindow:0x7fa4ea444b20 )>"
)
Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7fa4ea44d160 UIView:0x7fa4ea429290.centerY == UIView:0x7fa4ea4470f0.centerY>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
Can you help me?
Thanks a lot
Do you plan to have a squared UIView of width: 100 and Height: 100 centered inside the UIView of an UIViewController? If so, you may try one of the 6 following Auto Layout styles (Swift 5 / iOS 12.2):
1. Using NSLayoutConstraint initializer
override func viewDidLoad() {
let newView = UIView()
newView.backgroundColor = UIColor.red
view.addSubview(newView)
newView.translatesAutoresizingMaskIntoConstraints = false
let horizontalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0)
let verticalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0)
let widthConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 100)
let heightConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 100)
view.addConstraints([horizontalConstraint, verticalConstraint, widthConstraint, heightConstraint])
}
override func viewDidLoad() {
let newView = UIView()
newView.backgroundColor = UIColor.red
view.addSubview(newView)
newView.translatesAutoresizingMaskIntoConstraints = false
let horizontalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0)
let verticalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0)
let widthConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 100)
let heightConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 100)
NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint, widthConstraint, heightConstraint])
}
override func viewDidLoad() {
let newView = UIView()
newView.backgroundColor = UIColor.red
view.addSubview(newView)
newView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true
NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true
}
2. Using Visual Format Language
override func viewDidLoad() {
let newView = UIView()
newView.backgroundColor = UIColor.red
view.addSubview(newView)
newView.translatesAutoresizingMaskIntoConstraints = false
let views = ["view": view!, "newView": newView]
let horizontalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:[view]-(<=0)-[newView(100)]", options: NSLayoutConstraint.FormatOptions.alignAllCenterY, metrics: nil, views: views)
let verticalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:[view]-(<=0)-[newView(100)]", options: NSLayoutConstraint.FormatOptions.alignAllCenterX, metrics: nil, views: views)
view.addConstraints(horizontalConstraints)
view.addConstraints(verticalConstraints)
}
override func viewDidLoad() {
let newView = UIView()
newView.backgroundColor = UIColor.red
view.addSubview(newView)
newView.translatesAutoresizingMaskIntoConstraints = false
let views = ["view": view!, "newView": newView]
let horizontalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:[view]-(<=0)-[newView(100)]", options: NSLayoutConstraint.FormatOptions.alignAllCenterY, metrics: nil, views: views)
let verticalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:[view]-(<=0)-[newView(100)]", options: NSLayoutConstraint.FormatOptions.alignAllCenterX, metrics: nil, views: views)
NSLayoutConstraint.activate(horizontalConstraints)
NSLayoutConstraint.activate(verticalConstraints)
}
3. Using a mix of NSLayoutConstraint initializer and Visual Format Language
override func viewDidLoad() {
let newView = UIView()
newView.backgroundColor = UIColor.red
view.addSubview(newView)
newView.translatesAutoresizingMaskIntoConstraints = false
let views = ["newView": newView]
let widthConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:[newView(100)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: views)
let heightConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:[newView(100)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: views)
let horizontalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0)
let verticalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0)
view.addConstraints(widthConstraints)
view.addConstraints(heightConstraints)
view.addConstraints([horizontalConstraint, verticalConstraint])
}
override func viewDidLoad() {
let newView = UIView()
newView.backgroundColor = UIColor.red
view.addSubview(newView)
newView.translatesAutoresizingMaskIntoConstraints = false
let views = ["newView": newView]
let widthConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:[newView(100)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: views)
let heightConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:[newView(100)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: views)
let horizontalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0)
let verticalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0)
NSLayoutConstraint.activate(widthConstraints)
NSLayoutConstraint.activate(heightConstraints)
NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint])
}
override func viewDidLoad() {
let newView = UIView()
newView.backgroundColor = UIColor.red
view.addSubview(newView)
newView.translatesAutoresizingMaskIntoConstraints = false
let views = ["newView": newView]
let widthConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:[newView(100)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: views)
let heightConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:[newView(100)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: views)
NSLayoutConstraint.activate(widthConstraints)
NSLayoutConstraint.activate(heightConstraints)
NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0).isActive = true
}
4. Using UIView.AutoresizingMask
Note: Springs and Struts will be translated into corresponding auto layout constraints at runtime.
override func viewDidLoad() {
let newView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
newView.backgroundColor = UIColor.red
view.addSubview(newView)
newView.translatesAutoresizingMaskIntoConstraints = true
newView.center = CGPoint(x: view.bounds.midX, y: view.bounds.midY)
newView.autoresizingMask = [UIView.AutoresizingMask.flexibleLeftMargin, UIView.AutoresizingMask.flexibleRightMargin, UIView.AutoresizingMask.flexibleTopMargin, UIView.AutoresizingMask.flexibleBottomMargin]
}
5. Using NSLayoutAnchor
override func viewDidLoad() {
let newView = UIView()
newView.backgroundColor = UIColor.red
view.addSubview(newView)
newView.translatesAutoresizingMaskIntoConstraints = false
let horizontalConstraint = newView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
let verticalConstraint = newView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
let widthConstraint = newView.widthAnchor.constraint(equalToConstant: 100)
let heightConstraint = newView.heightAnchor.constraint(equalToConstant: 100)
view.addConstraints([horizontalConstraint, verticalConstraint, widthConstraint, heightConstraint])
}
override func viewDidLoad() {
let newView = UIView()
newView.backgroundColor = UIColor.red
view.addSubview(newView)
newView.translatesAutoresizingMaskIntoConstraints = false
let horizontalConstraint = newView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
let verticalConstraint = newView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
let widthConstraint = newView.widthAnchor.constraint(equalToConstant: 100)
let heightConstraint = newView.heightAnchor.constraint(equalToConstant: 100)
NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint, widthConstraint, heightConstraint])
}
override func viewDidLoad() {
let newView = UIView()
newView.backgroundColor = UIColor.red
view.addSubview(newView)
newView.translatesAutoresizingMaskIntoConstraints = false
newView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
newView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
newView.widthAnchor.constraint(equalToConstant: 100).isActive = true
newView.heightAnchor.constraint(equalToConstant: 100).isActive = true
}
6. Using intrinsicContentSize and NSLayoutAnchor
import UIKit
class CustomView: UIView {
override var intrinsicContentSize: CGSize {
return CGSize(width: 100, height: 100)
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
let newView = CustomView()
newView.backgroundColor = UIColor.red
view.addSubview(newView)
newView.translatesAutoresizingMaskIntoConstraints = false
let horizontalConstraint = newView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
let verticalConstraint = newView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint])
}
}
Result:
It helps me to learn visually, so this is a supplemental answer.
Boilerplate code
override func viewDidLoad() {
super.viewDidLoad()
let myView = UIView()
myView.backgroundColor = UIColor.blue
myView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(myView)
// Add constraints code here
// ...
}
Each of the following examples are independent of the others.
Pin left edge
myView.leading = leadingMargin + 20
Method 1: Anchor Style
let margins = view.layoutMarginsGuide
myView.leadingAnchor.constraint(equalTo: margins.leadingAnchor, constant: 20).isActive = true
In addition to leadingAnchor, there is also trailingAnchor, topAnchor, and bottomAnchor.
Method 2: NSLayoutConstraint Style
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.leadingMargin, multiplier: 1.0, constant: 20.0).isActive = true
In addition to .leading there is also .trailing, .top, and .bottom.
In addition to .leadingMargin there is also .trailingMargin, .topMargin, and .bottomMargin.
Set Width and Height
width = 200
height = 100
Method 1: Anchor Style
myView.widthAnchor.constraint(equalToConstant: 200).isActive = true
myView.heightAnchor.constraint(equalToConstant: 100).isActive = true
Method 2: NSLayoutConstraint Style
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 200).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true
Center in container
myView.centerX = centerX
myView.centerY = centerY
Method 1: Anchor Style
myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
Method 2: NSLayoutConstraint Style
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0).isActive = true
Notes
Anchor style is the preferred method over NSLayoutConstraint Style, however it is only available from iOS 9, so if you are supporting iOS 8 then you should still use NSLayoutConstraint Style.
The examples above showed just the one or two constraints that were being focused on. However, in order to properly place myView in my test project I needed to have four constraints.
Further Reading
Programmatically Creating Constraints documentation
If you want to fill your super view then I suggest the swifty way:
view.translatesAutoresizingMaskIntoConstraints = false
let attributes: [NSLayoutAttribute] = [.top, .bottom, .right, .left]
NSLayoutConstraint.activate(attributes.map {
NSLayoutConstraint(item: view, attribute: $0, relatedBy: .equal, toItem: view.superview, attribute: $0, multiplier: 1, constant: 0)
})
Other wise if you need non equal constraints check out NSLayoutAnchor as of iOS 9. Its often much easier to read that using NSLayoutConstraint directly:
view.translatesAutoresizingMaskIntoConstraints = false
view.topAnchor.constraint(equalTo: view.superview!.topAnchor).isActive = true
view.bottomAnchor.constraint(equalTo: view.superview!.bottomAnchor).isActive = true
view.leadingAnchor.constraint(equalTo: view.superview!.leadingAnchor, constant: 10).isActive = true
view.trailingAnchor.constraint(equalTo: view.superview!.trailingAnchor, constant: 10).isActive = true
We can easily do this with in swift 5.1
setup 1
subview align to view center
subview width height set using float
view.addSubview(myView1)
myView1.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
myView1.centerXAnchor.constraint(equalTo: view.centerXAnchor),
myView1.centerYAnchor.constraint(equalTo: view.centerYAnchor),
myView1.widthAnchor.constraint(equalToConstant: 100),
myView1.heightAnchor.constraint(equalToConstant: 100),
])
setup 2
subview align to view leading and top anchor
subview width set using view width height
view.addSubview(myView2)
myView2.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
myView2.leadingAnchor.constraint(equalTo: view.leadingAnchor,constant: 16),
myView2.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor,constant: 16),
myView2.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.3),
myView2.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.3)
])
Constraints for multiple views in playground.
swift 3+
var yellowView: UIView!
var redView: UIView!
override func loadView() {
// UI
let view = UIView()
view.backgroundColor = .white
yellowView = UIView()
yellowView.backgroundColor = .yellow
view.addSubview(yellowView)
redView = UIView()
redView.backgroundColor = .red
view.addSubview(redView)
// Layout
redView.translatesAutoresizingMaskIntoConstraints = false
yellowView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
yellowView.topAnchor.constraint(equalTo: view.topAnchor, constant: 20),
yellowView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
yellowView.widthAnchor.constraint(equalToConstant: 80),
yellowView.heightAnchor.constraint(equalToConstant: 80),
redView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20),
redView.trailingAnchor.constraint(equalTo: view.trailingAnchor,constant: -20),
redView.widthAnchor.constraint(equalToConstant: 80),
redView.heightAnchor.constraint(equalToConstant: 80)
])
self.view = view
}
In my opinion xcode playground is the best place for learning adding
constraints programmatically.
Basically it involved 3 steps
fileprivate func setupName() {
lblName.text = "Hello world"
// Step 1
lblName.translatesAutoresizingMaskIntoConstraints = false
//Step 2
self.view.addSubview(lblName)
//Step 3
NSLayoutConstraint.activate([
lblName.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
lblName.centerYAnchor.constraint(equalTo: self.view.centerYAnchor)
])
}
This puts label "hello world" in center of screen.
Please refer link Autolayout constraints programmatically
The problem, as the error message suggests, is that you have constraints of type NSAutoresizingMaskLayoutConstraints that conflict with your explicit constraints, because new_view.translatesAutoresizingMaskIntoConstraints is set to true.
This is the default setting for views you create in code. You can turn it off like this:
var new_view:UIView! = UIView(frame: CGRectMake(0, 0, 100, 100))
new_view.translatesAutoresizingMaskIntoConstraints = false
Also, your width and height constraints are weird. If you want the view to have a constant width, this is the proper way:
new_view.addConstraint(NSLayoutConstraint(
item:new_view, attribute:NSLayoutAttribute.Width,
relatedBy:NSLayoutRelation.Equal,
toItem:nil, attribute:NSLayoutAttribute.NotAnAttribute,
multiplier:0, constant:100))
(Replace 100 by the width you want it to have.)
If your deployment target is iOS 9.0 or later, you can use this shorter code:
new_view.widthAnchor.constraintEqualToConstant(100).active = true
Anyway, for a layout like this (fixed size and centered in parent view), it would be simpler to use the autoresizing mask and let the system translate the mask into constraints:
var new_view:UIView! = UIView(frame: CGRectMake(0, 0, 100, 100))
new_view.backgroundColor = UIColor.redColor();
view.addSubview(new_view);
// This is the default setting but be explicit anyway...
new_view.translatesAutoresizingMaskIntoConstraints = true
new_view.autoresizingMask = [ .FlexibleTopMargin, .FlexibleBottomMargin,
.FlexibleLeftMargin, .FlexibleRightMargin ]
new_view.center = CGPointMake(view.bounds.midX, view.bounds.midY)
Note that using autoresizing is perfectly legitimate even when you're also using autolayout. (UIKit still uses autoresizing in lots of places internally.) The problem is that it's difficult to apply additional constraints to a view that is using autoresizing.
Updated for Swift 3
import UIKit
class ViewController: UIViewController {
let redView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .red
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
setupAutoLayout()
}
func setupViews() {
view.backgroundColor = .white
view.addSubview(redView)
}
func setupAutoLayout() {
// Available from iOS 9 commonly known as Anchoring System for AutoLayout...
redView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
redView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20).isActive = true
redView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
redView.heightAnchor.constraint(equalToConstant: 300).isActive = true
// You can also modified above last two lines as follows by commenting above & uncommenting below lines...
// redView.topAnchor.constraint(equalTo: view.topAnchor, constant: 20).isActive = true
// redView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
}
Type of Constraints
/*
// regular use
1.leftAnchor
2.rightAnchor
3.topAnchor
// intermediate use
4.widthAnchor
5.heightAnchor
6.bottomAnchor
7.centerXAnchor
8.centerYAnchor
// rare use
9.leadingAnchor
10.trailingAnchor
etc. (note: very project to project)
*/
Auto layout is realized by applying constraints on images. Use NSLayoutConstraint. It is possible to implement an ideal and beautiful design on all devices. Please try the code below.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let myImageView:UIImageView = UIImageView()
myImageView.backgroundColor = UIColor.red
myImageView.image = UIImage(named:"sample_dog")!
myImageView.translatesAutoresizingMaskIntoConstraints = false
myImageView.layer.borderColor = UIColor.red.cgColor
myImageView.layer.borderWidth = 10
self.view.addSubview(myImageView)
view.removeConstraints(view.constraints)
view.addConstraint(NSLayoutConstraint(
item: myImageView,
attribute: .top,
relatedBy: .equal,
toItem: view,
attribute: .top,
multiplier: 1,
constant:100)
)
view.addConstraint(NSLayoutConstraint(
item: myImageView,
attribute: .centerX,
relatedBy: .equal,
toItem: view,
attribute: .centerX,
multiplier: 1,
constant:0)
)
view.addConstraint(NSLayoutConstraint(
item: myImageView,
attribute: .height,
relatedBy: .equal,
toItem: view,
attribute: .width,
multiplier: 0.5,
constant:40))
view.addConstraint(NSLayoutConstraint(
item: myImageView,
attribute: .width,
relatedBy: .equal,
toItem: view,
attribute: .width,
multiplier: 0.5,
constant:40))
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
the following code works for me in this scenario: an UIImageView forced landscape.
imagePreview!.isUserInteractionEnabled = true
imagePreview!.isExclusiveTouch = true
imagePreview!.contentMode = UIView.ContentMode.scaleAspectFit
// Remove all constraints
imagePreview!.removeAllConstraints()
// Add the new constraints
let guide = view.safeAreaLayoutGuide
imagePreview!.translatesAutoresizingMaskIntoConstraints = false
imagePreview!.leadingAnchor.constraint(equalTo: guide.leadingAnchor).isActive = true
imagePreview!.trailingAnchor.constraint(equalTo: guide.trailingAnchor).isActive = true
imagePreview!.heightAnchor.constraint(equalTo: guide.heightAnchor, multiplier: 1.0).isActive = true
where removeAllConstraints is an extension
extension UIView {
func removeAllConstraints() {
var _superview = self.superview
func removeAllConstraintsFromView(view: UIView) { for c in view.constraints { view.removeConstraint(c) } }
while let superview = _superview {
for constraint in superview.constraints {
if let first = constraint.firstItem as? UIView, first == self {
superview.removeConstraint(constraint)
}
if let second = constraint.secondItem as? UIView, second == self {
superview.removeConstraint(constraint)
}
}
_superview = superview.superview
}
self.removeConstraints(self.constraints)
self.translatesAutoresizingMaskIntoConstraints = true
}
}
If you find the above to be ugly. You should consider using a DSL for constraints. Such as SnapKit
Makes constraint API much more user-friendly
view.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
Would like to add some theoretical concept to Imanou Petit’s answer, so that one can understand how auto layout works.
To understand auto layout consider your view as rubber's object which is shrinked initially.
To place an object on screen we need 4 mandatory things :
X coordinate of object (horizontal position).
Y coordinate of object (vertical position )
Object’s Width
Object’s Height.
1 X coordinate: There are multiple ways of giving x coordinates to a view.
Such as Leading constraint, Trailing constraint , Horizontally centre
etc.
2 Y coordinate: There are multiple ways of giving y coordinates to a view :
Such as Top constraint, Bottom constraint , Vertical centre etc.
3 Object's width: There are two ways of giving width constrain to a view :
a. Add fixed width constraint (consider this constraint as iron rod of fixed width and you have hooked your rubber’s object horizontally with it so rubber’s object don’t shrink or expand)
b. Do not add any width constraint but add x coordinate constraint to both end of view trailing and leading, these two constraints will expand/shrink your rubber’s object by pulling/pushing it from both end, leading and trailing.
4 Object's height: Similar to width, there are two ways of giving height constraint to a view as well :
a. Add fixed height constraint (consider this constraints as iron rod of fixed height and you have hooked your rubber’s object vertically with it so rubber’s object don’t shrink or expand)
b. Do not add any height constraint but add x coordinate constraint to both end of view top and bottom, these two constraints will expand/shrink your rubber’s object pulling/pushing it from both end, top and bottom.
it is a little different in xcode 7.3.1. this is what i come up with
// creating the view
let newView = UIView()
newView.backgroundColor = UIColor.redColor()
newView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(newView)
// creating the constraint
// attribute and relation cannot be set directyl you need to create a cariable of them
let layout11 = NSLayoutAttribute.CenterX
let layout21 = NSLayoutRelation.Equal
let layout31 = NSLayoutAttribute.CenterY
let layout41 = NSLayoutAttribute.Width
let layout51 = NSLayoutAttribute.Height
let layout61 = NSLayoutAttribute.NotAnAttribute
// defining all the constraint
let horizontalConstraint = NSLayoutConstraint(item: newView, attribute: layout11, relatedBy: layout21, toItem: view, attribute: layout11, multiplier: 1, constant: 0)
let verticalConstraint = NSLayoutConstraint(item: newView, attribute: layout31, relatedBy: layout21, toItem: view, attribute: layout31, multiplier: 1, constant: 0)
let widthConstraint = NSLayoutConstraint(item: newView, attribute: layout41, relatedBy: layout21, toItem: nil, attribute: layout61, multiplier: 1, constant: 100)
let heightConstraint = NSLayoutConstraint(item: newView, attribute: layout51, relatedBy: layout21, toItem: nil, attribute: layout61, multiplier: 1, constant: 100)
// adding all the constraint
NSLayoutConstraint.activateConstraints([horizontalConstraint,verticalConstraint,widthConstraint,heightConstraint])
This is one way to adding constraints programmatically
override func viewDidLoad() {
super.viewDidLoad()
let myLabel = UILabel()
myLabel.labelFrameUpdate(label: myLabel, text: "Welcome User", font: UIFont(name: "times new roman", size: 40)!, textColor: UIColor.red, textAlignment: .center, numberOfLines: 0, borderWidth: 2.0, BorderColor: UIColor.red.cgColor)
self.view.addSubview(myLabel)
let myLabelhorizontalConstraint = NSLayoutConstraint(item: myLabel, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0)
let myLabelverticalConstraint = NSLayoutConstraint(item: myLabel, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0)
let mylabelLeading = NSLayoutConstraint(item: myLabel, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.leading, multiplier: 1, constant: 10)
let mylabelTrailing = NSLayoutConstraint(item: myLabel, attribute: NSLayoutAttribute.trailing, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.trailing, multiplier: 1, constant: -10)
let myLabelheightConstraint = NSLayoutConstraint(item: myLabel, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 50)
NSLayoutConstraint.activate(\[myLabelhorizontalConstraint, myLabelverticalConstraint, myLabelheightConstraint,mylabelLeading,mylabelTrailing\])
}
extension UILabel
{
func labelFrameUpdate(label:UILabel,text:String = "This is sample Label",font:UIFont = UIFont(name: "times new roman", size: 20)!,textColor:UIColor = UIColor.red,textAlignment:NSTextAlignment = .center,numberOfLines:Int = 0,borderWidth:CGFloat = 2.0,BorderColor:CGColor = UIColor.red.cgColor){
label.translatesAutoresizingMaskIntoConstraints = false
label.text = text
label.font = font
label.textColor = textColor
label.textAlignment = textAlignment
label.numberOfLines = numberOfLines
label.layer.borderWidth = borderWidth
label.layer.borderColor = UIColor.red.cgColor
}
}
var xCenterConstraint : NSLayoutConstraint!
var yCenterConstraint: NSLayoutConstraint!
xCenterConstraint = NSLayoutConstraint(item: self.view, attribute: .CenterX, relatedBy: .Equal, toItem: (Your view NAme), attribute: .CenterX, multiplier: 1, constant: 0)
self.view.addConstraint(xCenterConstraint)
yCenterConstraint = NSLayoutConstraint(item: self.view, attribute: .CenterY, relatedBy: .Equal, toItem: (Your view Name), attribute: .CenterY, multiplier: 1, constant: 0)
self.view.addConstraint(yCenterConstraint)
Try this elegant UIView extension for constraints. You can do constraints easy as:
- firstView.coverWholeSuperview()
- firstView.constraints(size: CGSize(width: 44, height: 44), centerX: view.centerXAnchor, centerY: view.centerXAnchor)
- firstView.constraints(top: view.topAnchor,
leading: secondView.leadingAnchor,
bottom: view.bottomAnchor,
trailing: secondView.trailingAnchor,
padding: UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12))
Here is extension, just copy it to your project.
extension UIView {
/// Attaches all sides of the receiver to its parent view
func coverWholeSuperview(margin: CGFloat = 0.0) {
let view = superview
layoutAttachTop(to: view, margin: margin)
layoutAttachBottom(to: view, margin: margin)
layoutAttachLeading(to: view, margin: margin)
layoutAttachTrailing(to: view, margin: margin)
}
/// Attaches the top of the current view to the given view's top if it's a superview of the current view
/// or to it's bottom if it's not (assuming this is then a sibling view).
#discardableResult
func layoutAttachTop(to: UIView? = nil, margin: CGFloat = 0.0) -> NSLayoutConstraint {
let view: UIView? = to ?? superview
let isSuperview = view == superview
let constraint = NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal,
toItem: view, attribute: isSuperview ? .top : .bottom, multiplier: 1.0,
constant: margin)
superview?.addConstraint(constraint)
return constraint
}
/// Attaches the bottom of the current view to the given view
#discardableResult
func layoutAttachBottom(to: UIView? = nil, margin: CGFloat = 0.0, priority: UILayoutPriority? = nil) -> NSLayoutConstraint {
let view: UIView? = to ?? superview
let isSuperview = (view == superview) || false
let constraint = NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal,
toItem: view, attribute: isSuperview ? .bottom : .top, multiplier: 1.0,
constant: -margin)
if let priority = priority {
constraint.priority = priority
}
superview?.addConstraint(constraint)
return constraint
}
/// Attaches the leading edge of the current view to the given view
#discardableResult
func layoutAttachLeading(to: UIView? = nil, margin: CGFloat = 0.0) -> NSLayoutConstraint {
let view: UIView? = to ?? superview
let isSuperview = (view == superview) || false
let constraint = NSLayoutConstraint(item: self, attribute: .leading, relatedBy: .equal,
toItem: view, attribute: isSuperview ? .leading : .trailing, multiplier: 1.0,
constant: margin)
superview?.addConstraint(constraint)
return constraint
}
/// Attaches the trailing edge of the current view to the given view
#discardableResult
func layoutAttachTrailing(to: UIView? = nil, margin: CGFloat = 0.0, priority: UILayoutPriority? = nil) -> NSLayoutConstraint {
let view: UIView? = to ?? superview
let isSuperview = (view == superview) || false
let constraint = NSLayoutConstraint(item: self, attribute: .trailing, relatedBy: .equal,
toItem: view, attribute: isSuperview ? .trailing : .leading, multiplier: 1.0,
constant: -margin)
if let priority = priority {
constraint.priority = priority
}
superview?.addConstraint(constraint)
return constraint
}
// For anchoring View
struct AnchoredConstraints {
var top, leading, bottom, trailing, width, height, centerX, centerY: NSLayoutConstraint?
}
#discardableResult
func constraints(top: NSLayoutYAxisAnchor? = nil, leading: NSLayoutXAxisAnchor? = nil, bottom: NSLayoutYAxisAnchor? = nil,
trailing: NSLayoutXAxisAnchor? = nil, padding: UIEdgeInsets = .zero, size: CGSize = .zero,
centerX: NSLayoutXAxisAnchor? = nil, centerY: NSLayoutYAxisAnchor? = nil,
centerXOffset: CGFloat = 0, centerYOffset: CGFloat = 0) -> AnchoredConstraints {
translatesAutoresizingMaskIntoConstraints = false
var anchoredConstraints = AnchoredConstraints()
if let top = top {
anchoredConstraints.top = topAnchor.constraint(equalTo: top, constant: padding.top)
}
if let leading = leading {
anchoredConstraints.leading = leadingAnchor.constraint(equalTo: leading, constant: padding.left)
}
if let bottom = bottom {
anchoredConstraints.bottom = bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom)
}
if let trailing = trailing {
anchoredConstraints.trailing = trailingAnchor.constraint(equalTo: trailing, constant: -padding.right)
}
if size.width != 0 {
anchoredConstraints.width = widthAnchor.constraint(equalToConstant: size.width)
}
if size.height != 0 {
anchoredConstraints.height = heightAnchor.constraint(equalToConstant: size.height)
}
if let centerX = centerX {
anchoredConstraints.centerX = centerXAnchor.constraint(equalTo: centerX, constant: centerXOffset)
}
if let centerY = centerY {
anchoredConstraints.centerY = centerYAnchor.constraint(equalTo: centerY, constant: centerYOffset)
}
[anchoredConstraints.top, anchoredConstraints.leading, anchoredConstraints.bottom,
anchoredConstraints.trailing, anchoredConstraints.width,
anchoredConstraints.height, anchoredConstraints.centerX,
anchoredConstraints.centerY].forEach { $0?.isActive = true }
return anchoredConstraints
}
}
You are adding all defined constraints to self.view which is wrong, as width and height constraint should be added to your newView.
Also, as I understand you want to set constant width and height 100:100.
In this case you should change your code to:
var constW = NSLayoutConstraint(item: newView,
attribute: .Width,
relatedBy: .Equal,
toItem: nil,
attribute: .NotAnAttribute,
multiplier: 1,
constant: 100)
newView.addConstraint(constW)
var constH = NSLayoutConstraint(item: newView,
attribute: .Height,
relatedBy: .Equal,
toItem: nil,
attribute: .NotAnAttribute,
multiplier: 1,
constant: 100)
newView.addConstraint(constH)
You can use Snapkit to set constraints programmatically.
class ViewController: UIViewController {
let rectView: UIView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
private func setupViews() {
rectView.backgroundColor = .red
view.addSubview(rectView)
rectView.snp.makeConstraints {
$0.center.equalToSuperview()
}
}
}
The error is caused by constrains automatically created from autoresizing mask, they are created because UIView property translatesAutoresizingMaskIntoConstraints is true by default.
Consider using BoxView to get rid of all manual constraint creation boilerplate, and make your code concize and readable. To make layout in question with BoxView is very easy:
boxView.items = [
new_view.boxed.centerX().centerY().relativeWidth(1.0).relativeHeight(1.0)
]
I'm attempting to layout all my constraints programmatically because I have to add and remove boxes based on user input. When I run a function which applies all my constraints in ViewDidLoad, it works great. But if I run it again, after removing them all, 2 of my labels disappear behind my navigation bar. I can't figure out why! Keep in mind if I never run the function pasted below, my screen is blank because I have no constraints on start up from the storyboard. My goal is to figure out why my label and button disappear when the same piece of code is run a second time.
Below is a picture when the code, which I'll post below, is run initially in ViewDidLoad:
Below is a picture when the same piece of code is run again afterwards when the next button is pressed. This is just a test, in the future I'll need to reset all my constraints after changing them:
And Below is a picture of the debug view hierarchy afterwards:
The code that creates the constraints is below. Keep in mind I have only 5 elements, my main view, scroll view, aglAltitudeLabel which is the label, nextButton which is the button, and aglAltitude which is the text input:
//Remove all pre-existing contraints
var constraints:NSArray = aglAltitudeLabel.constraints()
aglAltitudeLabel.removeConstraints(constraints)
constraints = aglAltitude.constraints()
aglAltitude.removeConstraints(constraints)
constraints = nextButton.constraints()
nextButton.removeConstraints(constraints)
constraints = scrollView.constraints()
scrollView.removeConstraints(constraints)
constraints = view.constraints()
self.view.removeConstraints(constraints)
constraints = calculateButton.constraints()
calculateButton.removeConstraints(constraints)
//Make scrollview fit normal View, accounting for Navigation bar
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|[first(\(self.view.frame.width))]|", options: nil, metrics: nil, views: ["first": scrollView]))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-64-[first(\(self.view.frame.height-64))]|", options: nil, metrics: nil, views: ["first": scrollView]))
//Set the heights for the label and button
let labelHeight = NSLayoutConstraint(item: aglAltitudeLabel, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 20)
scrollView.addConstraint(labelHeight)
let buttonHeight = NSLayoutConstraint(item: nextButton, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 30)
scrollView.addConstraint(buttonHeight)
//Setup the vertical layout
scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-8-[first(30)]-8-|", options: nil, metrics: nil, views: ["first": aglAltitude]))
//Setup the horizontal layout
scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|-8-[first(97)]-8-[second(>=100)]-8-[third(46)]-8-|", options: nil, metrics: nil, views: ["first": aglAltitudeLabel, "second": aglAltitude, "third": nextButton]))
//Align baselines - this also occurs with the option above of AlignAllBaselines and leaving this code out
let aglLabelBaseline = NSLayoutConstraint(item: aglAltitudeLabel, attribute: NSLayoutAttribute.Baseline, relatedBy: NSLayoutRelation.Equal, toItem: aglAltitude, attribute: NSLayoutAttribute.Baseline, multiplier: 1.0, constant: 0)
scrollView.addConstraint(aglLabelBaseline)
let nextButtonBaseline = NSLayoutConstraint(item: nextButton, attribute: NSLayoutAttribute.Baseline, relatedBy: NSLayoutRelation.Equal, toItem: aglAltitude, attribute: NSLayoutAttribute.Baseline, multiplier: 1.0, constant: 0)
scrollView.addConstraint(nextButtonBaseline)
self.view.layoutSubviews()
Thank you for any help. I'm sure I'm doing 55 things incorrectly.
Edit: If I change the last section of code from this:
//Align baselines - this also occurs with the option above of AlignAllBaselines and leaving this code out
let aglLabelBaseline = NSLayoutConstraint(item: aglAltitudeLabel, attribute: NSLayoutAttribute.Baseline, relatedBy: NSLayoutRelation.Equal, toItem: aglAltitude, attribute: NSLayoutAttribute.Baseline, multiplier: 1.0, constant: 0)
scrollView.addConstraint(aglLabelBaseline)
let nextButtonBaseline = NSLayoutConstraint(item: nextButton, attribute: NSLayoutAttribute.Baseline, relatedBy: NSLayoutRelation.Equal, toItem: aglAltitude, attribute: NSLayoutAttribute.Baseline, multiplier: 1.0, constant: 0)
scrollView.addConstraint(nextButtonBaseline)
To this:
//Align baselines - this also occurs with the option above of AlignAllBaselines and leaving this code out
let aglLabelBaseline = NSLayoutConstraint(item: aglAltitudeLabel, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: scrollView, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant: 14)
self.view.addConstraint(aglLabelBaseline)
let nextButtonBaseline = NSLayoutConstraint(item: nextButton, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: scrollView, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant: 8)
self.view.addConstraint(nextButtonBaseline)
it works exactly as I'd expect. Why the difference?
Without knowing what your requirements are, it's hard to give you good advice. Here is an example of how I might do it. I added all the views in code, and added background colors to the views so I could better see their layout. I'm assuming that the scroll view is only added once, and never removed, so it's constraints to self.view should only be added once in viewDidLoad. Same goes for the height of the the other views if you don't need to change them (notice that I add the height constraints to the view itself, not its superview). The only thing that needs to be removed and re-added are the constraints between the scroll view and its subviews.
class ViewController: UIViewController {
var aglAltitudeLabel = UILabel()
var aglAltitude = UITextField()
var nextButton = UIButton.buttonWithType(.System) as UIButton
var scrollView = UIScrollView()
var viewsDict: NSDictionary!
override func viewDidLoad() {
super.viewDidLoad()
aglAltitudeLabel.text = "AGL Altitude"
aglAltitudeLabel.backgroundColor = UIColor.lightGrayColor()
aglAltitudeLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
aglAltitude.setTranslatesAutoresizingMaskIntoConstraints(false)
aglAltitude.backgroundColor = UIColor.yellowColor()
aglAltitudeLabel.addConstraint(NSLayoutConstraint(item: aglAltitudeLabel, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 30))
scrollView.setTranslatesAutoresizingMaskIntoConstraints(false)
nextButton.setTranslatesAutoresizingMaskIntoConstraints(false)
nextButton.setTitle("Next", forState: .Normal)
nextButton.backgroundColor = UIColor.lightGrayColor()
nextButton.addConstraint(NSLayoutConstraint(item: nextButton, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 30))
self.view.addSubview(scrollView)
scrollView.addSubview(aglAltitude)
scrollView.addSubview(aglAltitudeLabel)
scrollView.addSubview(nextButton)
scrollView.backgroundColor = UIColor(red: 1, green: 1, blue: 0.8, alpha: 1)
viewsDict = ["scrollView": scrollView, "aglAltitudeLabel": aglAltitudeLabel, "aglAltitude":aglAltitude, "nextButton":nextButton] as NSDictionary
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|[scrollView]|", options: nil, metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-64-[scrollView]|", options: nil, metrics: nil, views: viewsDict))
self.redoConstraints()
}
#IBAction func redoConstraints() {
scrollView.removeConstraints(scrollView.constraints())
scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-8-[aglAltitude(30)]-8-|", options: nil, metrics: nil, views: viewsDict))
scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|-8-[aglAltitudeLabel(97)]-8-[aglAltitude(>=100)]-8-[nextButton(46)]-8-|", options: .AlignAllBottom , metrics: nil, views: viewsDict))
}
}
Notice that I took the fixed width and height out of the constraints for the scroll view. There's no need for that, and it would cause it to not work correctly on rotation.