Constraint based layout means just what it sounds like. Providing a list of constraints to how different views should be arranged, and then letting the system solve it. This sounds similar in practice to the ‘springs and struts’ system that any iOS developer should already be familiar with, with at least one major difference. You can apply constraints to sibling views, not only the superview. This small difference opens up a entirely new world of what is possible in setting up the layout of views. The API I have put together is heavily based on
CAConstraintLayoutManager and should be very quick to jump into if you have used that class before.
The code for the layout system can be found here
Here is a simple example of laying out two views, and applying some constraints to them.
//This is just here to provide us a reference so the rest of this example makes sense JWConstraintLayoutView *layoutView = nil; layoutView = [[JWConstraintLayoutView alloc] initWithFrame:CGRectMake(0,0,320,480)]; UIView *viewA = [[UIView alloc] initWithFrame:CGRectZero]; viewA.frame = CGRectMake(0.0,0.0,100.0,25.0); viewA.backgroundColor = [UIColor redColor]; [layoutView addConstraint:[JWConstraint constraintWithView:viewA attribute:kJWConstraintMidY relativeTo:nil attribute:kJWConstraintMidY]]; [layoutView addConstraint:[JWConstraint constraintWithView:viewA attribute:kJWConstraintMidX relativeTo:nil attribute:kJWConstraintMidX]]; [layoutView addSubview:viewA]; UIView *viewB = [[UIView alloc] init]; viewB.backgroundColor = [UIColor greenColor]; [layoutView addConstraint:[JWConstraint constraintWithView:viewB attribute:kJWConstraintWidth relativeTo:viewA attribute:kJWConstraintWidth]]; [layoutView addConstraint:[JWConstraint constraintWithView:viewB attribute:kJWConstraintMidX relativeTo:viewA attribute:kJWConstraintMidX]]; [layoutView addConstraint:[JWConstraint constraintWithView:viewB attribute:kJWConstraintMinY relativeTo:viewA attribute:kJWConstraintMaxY offset:10.0]]; [layoutView addConstraint:[JWConstraint constraintWithView:viewB attribute:kJWConstraintMaxY relativeTo:nil attribute:kJWConstraintMaxY offset:-10.0]]; [layoutView addSubview:viewB];
After layout you will see something similar to this
This example is a direct translation of Apple’s CAConstraintLayoutManger example. Other than the obvious API differences, the only real change is modifying which constraints are set on viewB, as CoreAnimation and UIKit have flipped coordinate spaces.
There are three classes related to the constraints system.
JWConstraintallows you to describe your constraints, here is its designated initializer.
- (id)initWithView:(UIView*)aView attribute:(JWConstraintAttribute)anAttribute relativeTo:(UIView*)aRelativeView attribute:(JWConstraintAttribute)aRelativeAttribute scale:(CGFloat)aScale offset:(CGFloat)aOffset;
nilhere means that the calculation is based on the superview.
result = (result * scale) + offset. They default to 1.0 and 0 respectively when using initializers that don’t expose them.
JWConstraintLayoutViewis the workhorse of the three. Internally it will manage all the constraints and perform the actual constraints calculations. Recalculation of the constraints graph, the most expensive part of this, only occurs when new constraints are added. Other than that you should treat this as any other view, and expect it to relayout its subviews based on its constraints. Any unconstrained view will be laid out according to its standard behavior using its
autoresizeMask. The layout view should be placed as the superview to any views that you want it to manage, contrary to how
A compilable and much more complicated example can be found here.