How to add constraints programmatically using Swift

前端 未结 17 1177
逝去的感伤
逝去的感伤 2020-11-21 23:07

I\'m trying to figure this out since last week without going any step further. Ok, so I need to apply some constraints programmatically

相关标签:
17条回答
  • 2020-11-21 23:20
        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)
    
    0 讨论(0)
  • 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:

    0 讨论(0)
  • 2020-11-21 23:24

    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
    
    0 讨论(0)
  • 2020-11-21 23:25

    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.

    0 讨论(0)
  • 2020-11-21 23:25

    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.

    0 讨论(0)
  • 2020-11-21 23:28

    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)
          ])
      

    0 讨论(0)
提交回复
热议问题