Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add constraints programmatically using Swift

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

like image 328
Sara Canducci Avatar asked Oct 03 '14 14:10

Sara Canducci


People also ask

What is Autolayout in Swift?

Auto Layout constraints allow us to create views that dynamically adjust to different size classes and positions. The constraints will make sure that your views adjust to any size changes without having to manually update frames or positions.

What is translatesAutoresizingMaskIntoConstraints?

translatesAutoresizingMaskIntoConstraints. A Boolean value that determines whether the view's autoresizing mask is translated into Auto Layout constraints.


2 Answers

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:

enter image description here

like image 153
Imanou Petit Avatar answered Oct 03 '22 17:10

Imanou Petit


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

enter image description here

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

enter image description here

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

enter image description here

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
like image 37
Suragch Avatar answered Oct 03 '22 18:10

Suragch