ConstraintMaker for Autolayout

Repository

https://github.com/hitenkmr/ConstraintMaker

What is ConstraintMaker?

ConstraintMaker allows you to bind views programmatically. It's a light-weight class which wraps AutoLayout with nice and clean syntax. ConstraintMaker provides its own NSLayoutConstraint resulting in code that is more concise and readable.

For Example clone the repo or just download and go to DemoProject and run it, After running the project you will find how easy it is to manage views programmatically with ConstraintMaker.swift class.

Difficulty with Autolayout

Suppose that we have to bind a view from the 4 ends to the superview with 50 margins, then we have to write a huge line of code.

let view1 = UIView.init()
   view1.translatesAutoresizingMaskIntoConstraints = false
   view1.backgroundColor = UIColor.red
   superView.addSubview(view1)
   superView.addConstraints([
   NSLayoutConstraint.init(item: view1, 
            attribute: NSLayoutAttribute.leading, 
            relatedBy: .equal, 
            toItem: self,
            attribute: NSLayoutAttribute.leading, 
            multiplier: 1.0, 
            constant: 20),
            NSLayoutConstraint.init(item: view1, 
            attribute: NSLayoutAttribute.trailing, 
            relatedBy: .equal, 
            toItem: self, 
            attribute: NSLayoutAttribute.trailing,
            multiplier: 1.0, 
            constant: 20),
            NSLayoutConstraint.init(item: view1, 
            attribute: NSLayoutAttribute.top, 
            relatedBy: .equal, 
            toItem: self, 
            attribute: NSLayoutAttribute.top, 
            multiplier: 1.0, 
            constant: 20),
            NSLayoutConstraint.init(item: view1, 
            attribute: NSLayoutAttribute.bottom, 
            relatedBy: .equal, 
            toItem: self, 
            attribute: NSLayoutAttribute.bottom,
            multiplier: 1.0, 
            constant: 20)
            ])

But using ConstraintMaker with just few lines of code you can have a workaround to make it possible.

view1.prepareForNewConstraints { (v) in
            //give leading space from superview
            v?.setLeadingSpaceFromSuperView(leadingSpace: 50)
            //give trailing space from superview
            v?.setTrailingSpaceFromSuperView(trailingSpace: -50)
            //give top space from superview
            v?.setTopSpaceFromSuperView(topSpace: 50)
            //give bottom space from superview
            v?.setBottomSpaceFromSuperView(bottomSpace: -50)
        }

What's in ConstraintMaker.swift class

We have an extension to the UIView which contains functions that can be very useful while wrapping the view in another view. Autolayout Engine is smart and does all the work for you but adding a view on its superview programmatically takes huge lines of code that we have mentioned above, but using this class one can easily make use of it with few lines of code.

  func prepareForNewConstraints(block : ((UIView?) -> ())!)
    {
        self.translatesAutoresizingMaskIntoConstraints = false
        block(self)
    }

If you want to use Auto Layout to dynamically calculate the size and position of your view, you must set 'translatesAutoresizingMaskIntoConstraints' property to false. This method is used to bind the view and with a callback it prepares view magically.

var topSpaceConstraint: NSLayoutConstraint? {
        get {
            return objc_getAssociatedObject(self, &Keys.TopSpaceConstraint) as? NSLayoutConstraint
        }
        set (newValue) {
            objc_setAssociatedObject(self, &Keys.TopSpaceConstraint, nil,
                                     objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            
            objc_setAssociatedObject(self, &Keys.TopSpaceConstraint, newValue,
                                     objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    var bottomSpaceConstraint: NSLayoutConstraint? {
        get {
            return objc_getAssociatedObject(self, &Keys.BottomSpaceConstraint) as? NSLayoutConstraint
        }
        set (newValue) {
            objc_setAssociatedObject(self, &Keys.BottomSpaceConstraint, nil,
                                     objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            
            objc_setAssociatedObject(self, &Keys.BottomSpaceConstraint, newValue,
                                     objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    var leadingSpaceConstraint: NSLayoutConstraint? {
        get {
            return objc_getAssociatedObject(self, &Keys.LeadingSpaceConstraint) as? NSLayoutConstraint
        }
        set (newValue) {
            objc_setAssociatedObject(self, &Keys.LeadingSpaceConstraint, nil,
                                     objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            
            objc_setAssociatedObject(self, &Keys.LeadingSpaceConstraint, newValue,
                                     objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    var trailingSpaceConstraint: NSLayoutConstraint? {
        get {
            return objc_getAssociatedObject(self, &Keys.TrailingSpaceConstraint) as? NSLayoutConstraint
        }
        set (newValue) {
            objc_setAssociatedObject(self, &Keys.TrailingSpaceConstraint, nil,
                                     objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            
            objc_setAssociatedObject(self, &Keys.TrailingSpaceConstraint, newValue,
                                     objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    
    var heightConstraint: NSLayoutConstraint? {
        get {
            return objc_getAssociatedObject(self, &Keys.HeightConstraint) as? NSLayoutConstraint
        }
        set (newValue) {
            objc_setAssociatedObject(self, &Keys.HeightConstraint, nil,
                                     objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            
            objc_setAssociatedObject(self, &Keys.HeightConstraint, newValue,
                                     objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    var widthConstraint: NSLayoutConstraint? {
        get {
            return objc_getAssociatedObject(self, &Keys.WidthConstraint) as? NSLayoutConstraint
        }
        set (newValue) {
            objc_setAssociatedObject(self, &Keys.WidthConstraint, nil,
                                     objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            
            objc_setAssociatedObject(self, &Keys.WidthConstraint, newValue,
                                     objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    var verticalSpaceConstraint: NSLayoutConstraint? {
        get {
            return objc_getAssociatedObject(self, &Keys.verticalSpaceConstraint) as? NSLayoutConstraint
        }
        set (newValue) {
            objc_setAssociatedObject(self, &Keys.verticalSpaceConstraint, nil,
                                     objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            
            objc_setAssociatedObject(self, &Keys.verticalSpaceConstraint, newValue,
                                     objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

While setting the constraints on views you can get them at runtime also with Computed properties containing the getters and setters. While setting the specific constraint constant we have user association policy retain-nonatomic which keeps the strong reference to the object.
OBJC_ASSOCIATION_RETAIN_NONATOMIC Specifies a strong reference to the associated object, and that the association is not made atomically.

How to use the class

Just go to the repository and download the ConstraintMaker.swift class and drag and drop it into the project directory.
Suppose that we have to add a view called redView to the ViewController view programmatically so that it have 50 margin from left, right and top and height of 200. So just with few lines of code, this can be achieved.

  let redView = UIView.init()
        redView.backgroundColor = UIColor.red
        self.view.addSubview(redView)
        
        //If you want to use Auto Layout to dynamically calculate the size and position of your view, you must set 'translatesAutoresizingMaskIntoConstraints' property to false
        redView.prepareForNewConstraints { (v) in
            //give leading space from superview
            v?.setLeadingSpaceFromSuperView(leadingSpace: 50)
            //give trailing space from superview
            v?.setTrailingSpaceFromSuperView(trailingSpace: -50)
            //give top space from superview
            v?.setTopSpaceFromSuperView(topSpace: 50)
            //give bottom space from superview
            v?.pinHeightConstraint(constant: 200)
        }

Now suppose that we have to add another view called greenView, to make it center horizontally to the superview, vertical space from greenView of 20, width 100 and height 100.

let greenView = UIView.init()
        greenView.backgroundColor = UIColor.green
        self.view.addSubview(greenView)
        
        //If you want to use Auto Layout to dynamically calculate the size and position of your view, you must set 'translatesAutoresizingMaskIntoConstraints' property to false
        greenView.prepareForNewConstraints { (v) in
            //center Horizontally view to superview
            v?.centerHorizontallyWithView(view: self.view)
            //give vertical space from nearest neighbour
            v?.setVerticalSpaceFrom(toView: redView, constant: 20)
            //pin width
            v?.pinWidthConstraint(constant: 100)
            //pin height
            v?.pinHeightConstraint(constant: 100)
        }
H2
H3
H4
3 columns
2 columns
1 column
Join the conversation now
Logo
Center