How to add constraints programmatically using Swift

前端 未结 17 1178
逝去的感伤
逝去的感伤 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:29

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

    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
        }
    }
    

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

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

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

    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.

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

    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)
    
    0 讨论(0)
提交回复
热议问题