AfroLayout 0.2.0

AfroLayout 0.2.0

TestsTested
LangLanguage SwiftSwift
License MIT
ReleasedLast Release Feb 2017
SwiftSwift Version 3.0
SPMSupports SPM

Maintained by Wilhelm Van Der Walt, Martin Nygren.



  • By
  • Wilhelm

AfroLayout

Why AfroLayout was built

AfroLayout is a swift library that puts the auto back into AutoLayout.

  1. How it began
  2. Requirements
  3. Integration
  4. Usage

How it began

For simple projects with simple UI and UX, storyboards are perfect. They can be thrown together quickly and allow for quick feedback to design changes. It also allows you to make customisations to elements on the storyboards with the use of IBOutlets and IBActions. However as a project grows and the UI becomes more complex your storyboards can introduce bad practices like showing and hiding elements based on some state. They can also become misleading because a glance at a storyboard doesn’t illustrate the different states a view can have and as a result give emphasis to one particular state and makes the others difficult to change.

So if you go full circle and move your view layout code into your source files you end up with methods like this (and much worse in some cases 😬) Screenshot of update constraints method

The final nail in the coffin is if you require animation. To do animations require keeping reference to the appropriate constraints and doing the UIView.animationwithduration dance remembering all the caveats. The advantages of using Autolayout all of sudden start to feel not worth the hassle.

Enter AfroLayout. This library reduces the amount of work you need to do to maintain constraints in code. It also lets you animate your views with the power of the AutoLayout engine and the effort of frame animations

Requirements

  • iOS 7.0
  • Xcode 7

Integration

Manually (iOS 7+, OS X 10.9+)

To use this library in your project manually you may:

  1. for Projects, just drag AfroLayout.swift to the project tree

Usage

Everyday constraints

AfroLayout has one fundamental method that allows for easy adding of constraints to views. This method has been further abstracted into helper methods that apply default values for commonly used constraints. If any of these methods don’t suit your needs you can alway fall back to the custom constraints method.

In all the methods below notice the support for UILayoutSupport

Constrain to top of view

See screenshot

    self.wrapperView.constrainToTopOfView(viewController.view, topLayoutGuide: viewController.topLayoutGuide)
    view1.constrainToTopOfView(self.wrapperView)
Constrain to top left of view

See screenshot

    self.wrapperView.constrainToTopLeftOfView(viewController.view, topLayoutGuide: viewController.topLayoutGuide)
    view1.constrainToTopLeftOfView(self.wrapperView)
Constrain to top right of view

See screenshot

    self.wrapperView.constrainToTopRightOfView(viewController.view, topLayoutGuide: viewController.topLayoutGuide)
    view1.constrainToTopRightOfView(self.wrapperView)
Constrain to bottom view

See screenshot

    self.wrapperView.constrainToBottomOfView(viewController.view, bottomLayoutGuide: viewController.bottomLayoutGuide)
    view1.constrainToBottomOfView(self.wrapperView)
Constrain to bottom left view

See screenshot

    self.wrapperView.constrainToBottomLeftOfView(viewController.view, bottomLayoutGuide: viewController.bottomLayoutGuide)
    view1.constrainToBottomLeftOfView(self.wrapperView)
Constrain to bottom right view

See screenshot

    self.wrapperView.constrainToBottomRightOfView(viewController.view, bottomLayoutGuide: viewController.bottomLayoutGuide)
    view1.constrainToBottomRightOfView(self.wrapperView)
Constrain after view

See screenshot

    view1.constrainAfterView(self.wrapperView, inView: self.view)
    view2.constrainAfterView(self.wrapperView, inView: self.view, allign: .CenterY, horizontalPadding: 32)
    view3.constrainAfterView(self.wrapperView, inView: self.view, allign: .Bottom)
Constrain before view

See screenshot

    view1.constrainBeforeView(self.wrapperView, inView: self.view)
    view2.constrainBeforeView(self.wrapperView, inView: self.view, allign: .CenterY, horizontalPadding: -32)
    view3.constrainBeforeView(self.wrapperView, inView: self.view, allign: .Bottom)
Constrain below view

See screenshot

    view1.constrainBelowView(self.wrapperView, inView: self.view)
    view2.constrainBelowView(self.wrapperView, inView: self.view, allign: .CenterX, verticalPadding: 32)
    view3.constrainBelowView(self.wrapperView, inView: self.view, allign: .Trailing)
Constrain On top of view

See screenshot

    view1.constrainOnTopOfView(self.wrapperView, inView: self.view)
    view2.constrainOnTopOfView(self.wrapperView, inView: self.view, allign: .CenterX, verticalPadding: -32)
    view3.constrainOnTopOfView(self.wrapperView, inView: self.view, allign: .Trailing)
Add bottom constraint

This is most used when you are laying out views in a scrollView and you just want to quickly add the bottom constraint to the scrollview so that the scrollview knows how to size its content view.

    view1.addBottomConstraint(self.scrollView)

The bedrock of AfroLayout

Almost all of AfroLayout is built around the following method:

    public func addCustomConstraints(
        inView superView: UIView,
        toViews views: [UIView]? = nil,
        selfAttributes: [NSLayoutAttribute],
        relations: [NSLayoutRelation]? = nil,
        otherViewAttributes: [NSLayoutAttribute]? = nil,
        multipliers: [CGFloat]? = nil,
        padding: [CGFloat]? = nil,
        priorities: [UILayoutPriority]? = nil)
            -> [NSLayoutConstraint] {
            //... 
        }

This method allows you to turn this:

    self.wrapperView.addConstraints([
            NSLayoutConstraint(
            item: view1, 
            attribute: NSLayoutAttribute.Top, 
            relatedBy: NSLayoutRelation.Equal, 
            toItem: self.wrapperView, 
            attribute: NSLayoutAttribute.Top, 
            multiplier: 1.0, 
            constant: 0.0),

            NSLayoutConstraint(
            item: view1, 
            attribute: NSLayoutAttribute.Leading, 
            relatedBy: NSLayoutRelation.Equal, 
            toItem: self.wrapperView, 
            attribute: NSLayoutAttribute.Leading, 
            multiplier: 1.0, 
            constant: 0.0),

            NSLayoutConstraint(
            item: view1, 
            attribute: NSLayoutAttribute.Trailing, 
            relatedBy: NSLayoutRelation.Equal, 
            toItem: self.wrapperView, 
            attribute: NSLayoutAttribute.Trailing, 
            multiplier: 1.0, 
            constant: 0.0),

            NSLayoutConstraint(item: view1, 
            attribute: NSLayoutAttribute.Bottom, 
            relatedBy: NSLayoutRelation.Equal, 
            toItem: self.wrapperView, 
            attribute: NSLayoutAttribute.Bottom, 
            multiplier: 1.0, 
            constant: 0.0)
            ])

Into this:

        view1.addCustomConstraints(inView: self.wrapperView1, selfAttributes: [.Top, .Leading, .Trailing, .Bottom])

This is possible because appropriate defaults are applied to fill values that are predominantly the same. For example The multiplier in the NSLayoutConstraint is usually 1.0. You usually constrain the top of a view to a top of another view and you usually constrain something to its superview. However, there are many ways that to add constraints and this method gives you the utility to be as specific as you want while still being able to make sense of your constraints by looking at one method. For example,

    self.wrapperView3.addCustomConstraints(inView: self.view,
            toViews: [self.wrapperView2, self.wrapperView1, self.wrapperView2],
            selfAttributes: [.Top, .Leading, .Trailing],
            otherViewAttributes: [.Bottom, .Leading, .Trailing],
            relations: [.GreaterThanOrEqual, .Equal, .LessThanOrEqual],
            padding: [8.0, 0.0, 0.0],
            priorities: [750.0, 800.0, 500.0])

UILayoutSupport support

Caveats

Author

Wilhelm, [email protected]

License

AfroLayout is available under the MIT license. See the LICENSE file for more info.