Keep Layout makes Auto Layout much easier to use from code! No more Interface Builder or Visual Format. Keep Layout provides simple, more readable and powerful API for creating and accessing existing constraints.
Before you start, you should be familiar with Auto Layout topic. How it works and what's the point?
Project Status: All planned features are implemented and functional. Project is maintained and kept up to date with latest iOS/OS X. Feel free to submit Issues or Pull Requests.
Swift Adoperts: Some cool features introduced recently broke compatibility with Swift. Check out the Swift compatible branch. This branch will be updated along with the master
.
Origins: This library was originally made for this app here, especially for its iPad interface.
Every view has several attributes that are represented by KeepAttribute
class.
- Dimensions: width, height, aspect ratio
- Insets to superview: top, bottom, left, right
- Insets to superview margins: top, bottom, left, right
- Position in superview: horizontal and vertical
- Offsets to other views: top, bottom, left, right
- Alignments with other views: top, bottom, left, right, horizontal, vertical, first & last baselines
They can be accessed by calling methods on UIView
/NSView
object with one of these format:
@property (readonly) KeepLayout *keep<AttributeName>;
@property (readonly) KeepLayout *(^keep<AttributeName>To)(UIView *)); // Returns block taking another view.
Example:
KeepAttribute *width = view.keepWidth;
KeepAttribute *topOffset = view.keepTopOffsetTo(anotherView); // Invoking the block that returns the actual attribute.
Calling such method for the first time creates the attribute object and any subsequent calls will return the same object. For attributes related to other views this is true for each pair of views. Sometimes even in inversed order or direction:
// aligns are the same regardless of order
viewOne.keepLeftAlign(viewTwo) == viewTwo.keepLeftAlign(viewOne)
// left offset from 1 to 2 is right offset from 2 to 1
viewOne.keepLeftOffset(viewTwo) == viewTwo.keepRightOffset(viewOne)
See KeepView.h
for more.
Attributes have three properties: equal, min and max. These are not just plain scalar values, but may have associated a priority.
Priority is Required by default, but you can specify arbitrary priority using provided macros:
KeepValue value = 42; // value 42 at priority 1000
value = 42 +keepHigh; // value 42 at priority 750
value = 42 +keepLow; // value 42 at priority 250
value = 42 +keepFitting; // value 42 at priority 50
// Arbitrary priority:
value = 42 +keepAt(800); // value 42 at priority 800
Priorities are redeclared as KeepPriority
using UILayoutPriority
values and they use similar naming:
Required > High > Low > Fitting
1000 750 250 50
See KeepTypes.h
for more.
Keep width of the view to be equal to 150:
view.keepWidth.equal = 150;
Keep top inset to superview of the view to be at least 10:
view.keepTopInset.min = 10;
Don't let the first view to get closer than 10 to the second from the left:
firstView.keepLeftOffsetTo(secondView).min = 10;
You will often want to set multiple attributes to the same value. For this we have grouped attributes.
You can create groups at your own:
KeepAttribute *leftInsets = [KeepAttribute group:
viewOne.keepLeftInset,
viewTwo.keepLeftInset,
viewThree.keepLeftInset,
nil];
leftInsets.equal = 10;
However there are already some accessors to some of them:
view.keepSize // group of both Width and Height
view.keepInsets // group of all four insets
view.keepCenter // group of both axis of position
view.keepEdgeAlignTo // group of alignments to all four edges
See KeepView.h
or KeepAttribute.h
for more .
Atomic Groups are a way to deactivate multiple attributes at once. With atomic group you can quickly change one desired set of constraints (= layout) to another.
// Create atomic group
KeepAtomic *layout = [KeepAtomic layout:^{
self.view.keepWidth.min = 320 +keepHigh; // Set minimum width limit.
self.view.keepVerticalInsets.equal = 0; // Vertically stretch to fit.
}];
[layout deactivate];
// self.view no longer has minimum width of 320 and is no longer stretched vertically.
You can also deactivate them manually using:
self.view.keepWidth.min = KeepNone; // Removes minimum width constraint.
[self.view.keepWidth deactivate]; // Removes all constraints for width.
See KeepAttribute.h
for details.
For the most used cases there are convenience methods. Nothing you could write yourself, but simplify your code and improve readability. Some of them:
[view keepSize:CGSizeMake(100, 200)];
[view keepInsets:UIEdgeInsetsMake(10, 20, 30, 40)];
[view keepCentered];
See KeepView.h
for more.
Most of the methods added to UIView
/NSView
class can also be called on any array on views. Such call creates grouped attribute of all contained view attributes:
NSArray *views = @[ viewOne, viewTwo, viewThree ];
views.keepInsets.min = 10;
The above code creates and configures 12 layout constraints!
In addition, arrays allow you to use related attributes more easily, using another convenience methods:
NSArray *views = @[ viewOne, viewTwo, viewThree ];
[views keepWidthsEqual];
[views keepHorizontalOffsets:20];
[views keepTopAligned];
You just created 6 new layout constraints, did you notice?
See NSArray+KeepLayout.h
for more.
Constraints can be animated. You can use simple UIView
block animation, but you need to call -layoutIfNeeded
at the end of animation block. That triggers -layoutSubviews
which applies new constraints.
Or you can use one of the provided methods so you don't need to care:
view.keepWidth.equal = 100;
[view.superview keepAnimatedWithDuration:1 layout:^{
view.keepWidth.equal = 200;
}];
These are instance methods and must be called on parent view of all affected subviews. At the end of layout block this view receives -layoutIfNeeded
method. Any changes to views out of the receiver's subview tree will not be animated.
Spring animation from iOS 7 included, animations on OS X are not supported yet.
See KeepView.h
for more.
KeepLayout adds lazy-loaded invisible .keepLayoutView
to every UIViewController
in a category. This view is aligned with Top & Bottom Layout Guide and Left & Right Margins of the view controller, which means its size represents visible portion of the view controller. You can use this Layout View to align your views with translucent bars (navigation bar, toolbar, status bar or tab bar).
imageView.keepEdgeAlignTo(controller.keepLayoutView).equal = 0;
// imageView will not be covered by UINavigationBar or UITabBar
See UIViewController+KeepLayout.h
for more.
Keep Layout uses its own NSLayoutConstraint
subclass that overrides -debugDescription
method. Once you get error message Unable to simultaneously satisfy constraints.
, you will see nicely readable description of every constraint you have created. Example:
"<KeepLayoutConstraint:0xc695560 left offset of <YourView 0xc682cf0> to <YourAnotherView 0xc681350> equal to 20 with required priority>",
"<KeepLayoutConstraint:0xc695560 left offset of <YourView 0xc682cf0> to <YourAnotherView 0xc681350> equal to 50 with required priority>",
With this you can very easily find the wrong attribute and fix it.
See KeepLayoutConstraint.h
for details.
Once the attribute is accessed it is created and associated with given view (runtime asociation). In case of related attribbutes, the second view is used as weak key in NSMapTable
.
See UIView+KeepLayout.m
for details.
KeepValue
is declared as _Complex double
, which allows seamless convertibility from and to double
. The priority is stored as imaginary part.
See KeepTypes.h
for details.
Each attribute manages up to three constraints (NSLayoutConstraint
) that are created, updated and removed when needed. One constraint for each of three relations (NSLayoutRelation
enum) and setting equal
, min
or max
properties modifies them.
See KeepAttribute.m
for details.
KeepAttribute
class is a class cluster with specific subclasses. One that manages constraints using constant
value, one for constraints using multiplier
and one grouping subclass that forwards primitive methods to its contained children.
See KeepAttribute.m
for details.
Array methods usually call the same selector on contained views and return group of returned attributes.
See NSArray+KeepLayout.m
for details.
Animation delay is implemented as real execution delay, not just delay for animating the changes. This differs from UIView
block animations and allows you to set up animations in the same update cycle as your initial layout.
See KeepView.m
for details.
Version 1.6.0
MIT License, Copyright © 2013-2014 Martin Kiss
THE SOFTWARE IS PROVIDED "AS IS", and so on...
see LICENSE.md
more.