##Why AfroLayout was built
AfroLayout is a swift library that puts the auto back into AutoLayout.
##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 😬)
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
- iOS 7.0
- Xcode 7
##Integration
####CocoaPods (iOS 8+, OS X 10.9+)
You can use CocoaPods to install AfroLayout
by adding it to your Podfile
:
platform :ios, '8.0'
use_frameworks!
target 'MyApp' do
pod 'AfroLayout', :git => 'https://github.com/va3093/AfroLayout.git'
end
Note that this requires CocoaPods version 36, and your iOS deployment target to be at least 8.0:
####Carthage (iOS 8+, OS X 10.9+)
You can use Carthage to install AfroLayout
by adding it to your Cartfile
:
github "va3093/afrolayout"
####Manually (iOS 7+, OS X 10.9+)
To use this library in your project manually you may:
- for Projects, just drag AfroLayout.swift to the project tree
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
See screenshot
self.wrapperView.constrainToTopOfView(viewController.view, topLayoutGuide: viewController.topLayoutGuide)
view1.constrainToTopOfView(self.wrapperView)
See screenshot
self.wrapperView.constrainToTopLeftOfView(viewController.view, topLayoutGuide: viewController.topLayoutGuide)
view1.constrainToTopLeftOfView(self.wrapperView)
See screenshot
self.wrapperView.constrainToTopRightOfView(viewController.view, topLayoutGuide: viewController.topLayoutGuide)
view1.constrainToTopRightOfView(self.wrapperView)
See screenshot
self.wrapperView.constrainToBottomOfView(viewController.view, bottomLayoutGuide: viewController.bottomLayoutGuide)
view1.constrainToBottomOfView(self.wrapperView)
See screenshot
self.wrapperView.constrainToBottomLeftOfView(viewController.view, bottomLayoutGuide: viewController.bottomLayoutGuide)
view1.constrainToBottomLeftOfView(self.wrapperView)
See screenshot
self.wrapperView.constrainToBottomRightOfView(viewController.view, bottomLayoutGuide: viewController.bottomLayoutGuide)
view1.constrainToBottomRightOfView(self.wrapperView)
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)
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)
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)
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)
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)
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])
Wilhelm, va3093@gmail.com
AfroLayout is available under the MIT license. See the LICENSE file for more info.