<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>NSZombie</title>
 <link href="http://nszombie.com/atom.xml" rel="self"/>
 <link href="http://nszombie.com/"/>
 <updated>2011-04-06T09:51:28-07:00</updated>
 <id>http://nszombie.com/</id>
 <author>
   <name>Josh Weinberg</name>
   <email>joshuacweinberg@gmail.com</email>
 </author>

 
 <entry>
   <title>Constraint Based Layout for iOS</title>
   <link href="http://nszombie.com/2010/12/08/ConstraintBasedLayout.html"/>
   <updated>2010-12-08T00:00:00-08:00</updated>
   <id>http://nszombie.com/2010/12/08/ConstraintBasedLayout</id>
   <content type="html">&lt;h1&gt;&lt;a href=&quot;/2010/12/08/ConstraintBasedLayout.html&quot;&gt;Constraint Based Layout for iOS&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;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 &amp;#8216;springs and struts&amp;#8217; 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 &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; I have put together is heavily based on &lt;code&gt;CAConstraintLayoutManager&lt;/code&gt; and should be very quick to jump into if you have used that class before.&lt;/p&gt;
&lt;p&gt;The code for the layout system can be found &lt;a href=&quot;https://github.com/jweinberg/JWLayoutViews/&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Using JWConstraintLayoutView&lt;/h2&gt;
&lt;p&gt;Here is a simple example of laying out two views, and applying some constraints to them.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;objectivec&quot;&gt;&lt;span class=&quot;c1&quot;&gt;//This is just here to provide us a reference so the rest of this example makes sense&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;JWConstraintLayoutView&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layoutView&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;layoutView&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JWConstraintLayoutView&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;initWithFrame:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CGRectMake&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;320&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;480&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)];&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;UIView&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewA&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIView&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;initWithFrame:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CGRectZero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;viewA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;frame&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CGRectMake&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;100.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;25.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;viewA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;backgroundColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIColor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layoutView&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;addConstraint:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JWConstraint&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;constraintWithView:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewA&lt;/span&gt;
                                                 &lt;span class=&quot;nl&quot;&gt;attribute:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kJWConstraintMidY&lt;/span&gt;
                                                &lt;span class=&quot;nl&quot;&gt;relativeTo:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;nil&lt;/span&gt;
                                                 &lt;span class=&quot;nl&quot;&gt;attribute:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kJWConstraintMidY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]];&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layoutView&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;addConstraint:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JWConstraint&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;constraintWithView:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewA&lt;/span&gt;
                                                 &lt;span class=&quot;nl&quot;&gt;attribute:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kJWConstraintMidX&lt;/span&gt;
                                                &lt;span class=&quot;nl&quot;&gt;relativeTo:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;nil&lt;/span&gt;
                                                 &lt;span class=&quot;nl&quot;&gt;attribute:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kJWConstraintMidX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]];&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layoutView&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;addSubview:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;UIView&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewB&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIView&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;viewB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;backgroundColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIColor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;greenColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layoutView&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;addConstraint:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JWConstraint&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;constraintWithView:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewB&lt;/span&gt;
                                                 &lt;span class=&quot;nl&quot;&gt;attribute:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kJWConstraintWidth&lt;/span&gt;
                                                &lt;span class=&quot;nl&quot;&gt;relativeTo:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewA&lt;/span&gt;
                                                 &lt;span class=&quot;nl&quot;&gt;attribute:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kJWConstraintWidth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]];&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layoutView&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;addConstraint:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JWConstraint&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;constraintWithView:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewB&lt;/span&gt;
                                                 &lt;span class=&quot;nl&quot;&gt;attribute:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kJWConstraintMidX&lt;/span&gt;
                                                &lt;span class=&quot;nl&quot;&gt;relativeTo:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewA&lt;/span&gt;
                                                 &lt;span class=&quot;nl&quot;&gt;attribute:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kJWConstraintMidX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]];&lt;/span&gt;


&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layoutView&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;addConstraint:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JWConstraint&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;constraintWithView:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewB&lt;/span&gt;
                                                 &lt;span class=&quot;nl&quot;&gt;attribute:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kJWConstraintMinY&lt;/span&gt;
                                                &lt;span class=&quot;nl&quot;&gt;relativeTo:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewA&lt;/span&gt;
                                                 &lt;span class=&quot;nl&quot;&gt;attribute:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kJWConstraintMaxY&lt;/span&gt;
                                                    &lt;span class=&quot;nl&quot;&gt;offset:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]];&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layoutView&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;addConstraint:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JWConstraint&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;constraintWithView:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewB&lt;/span&gt;
                                                 &lt;span class=&quot;nl&quot;&gt;attribute:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kJWConstraintMaxY&lt;/span&gt;
                                                &lt;span class=&quot;nl&quot;&gt;relativeTo:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;nil&lt;/span&gt;
                                                 &lt;span class=&quot;nl&quot;&gt;attribute:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kJWConstraintMaxY&lt;/span&gt;
                                                    &lt;span class=&quot;nl&quot;&gt;offset:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]];&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layoutView&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;addSubview:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;After layout you will see something similar to this&lt;br /&gt;
&lt;center&gt;&lt;img src=&quot;/images/constraints-1.png&quot; title=&quot;Constraints&quot; alt=&quot;Constraints&quot; /&gt;&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;This example is a direct translation of Apple&amp;#8217;s &lt;a href=&quot;http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreAnimation_guide/Articles/Layout.html#//apple_ref/doc/uid/TP40006084-SW5&quot;&gt;CAConstraintLayoutManger example&lt;/a&gt;. Other than the obvious &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; differences, the only real change is modifying which constraints are set on viewB, as CoreAnimation and UIKit have flipped coordinate spaces.&lt;/p&gt;
&lt;p&gt;There are three classes related to the constraints system.&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;strong&gt;JWConstraintGraphNode&lt;/strong&gt;&lt;br /&gt;
This is a internal class used by the constraint solving system. You should never have to create one of these manually, or really care about them. I only bring it up here so that you are aware of its existence.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;JWConstraint&lt;/strong&gt;&lt;br /&gt;
&lt;code&gt;JWConstraint&lt;/code&gt; allows you to describe your constraints, here is its designated initializer.&lt;br /&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;objc&quot;&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;initWithView:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIView&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aView&lt;/span&gt;
         &lt;span class=&quot;nl&quot;&gt;attribute:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JWConstraintAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;anAttribute&lt;/span&gt; 
        &lt;span class=&quot;nl&quot;&gt;relativeTo:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIView&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aRelativeView&lt;/span&gt; 
         &lt;span class=&quot;nl&quot;&gt;attribute:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JWConstraintAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aRelativeAttribute&lt;/span&gt; 
             &lt;span class=&quot;nl&quot;&gt;scale:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CGFloat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aScale&lt;/span&gt; 
            &lt;span class=&quot;nl&quot;&gt;offset:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CGFloat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aOffset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

	&lt;ul&gt;
		&lt;li&gt;&lt;strong&gt;aView&lt;/strong&gt; is the view on which you are applying the constraint.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;anAttribute&lt;/strong&gt; is the attribute on the view which will be calculated. You can only constrain up to two attributes per axis, per view. Meaning only MinX and Width, or MaxX and MidX, but MinX, MidX and Width all together.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;aRelativeView&lt;/strong&gt; is the view which you want to base the calculation on. A value of &lt;code&gt;nil&lt;/code&gt; here means that the calculation is based on the superview.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;aRelativeAttribute&lt;/strong&gt; is the attribute to base the previous attribute on. Any attribute here is valid, even if it is not on the same axis as the input attribute.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;aScale&lt;/strong&gt; and &lt;strong&gt;aOffset&lt;/strong&gt; are applied to the result as &lt;code&gt;result = (result * scale) + offset&lt;/code&gt;. They default to 1.0 and 0 respectively when using initializers that don&amp;#8217;t expose them.&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;JWConstraintLayoutView&lt;/strong&gt;&lt;br /&gt;
&lt;code&gt;JWConstraintLayoutView&lt;/code&gt; is 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 &lt;code&gt;autoresizeMask&lt;/code&gt;. The layout view should be placed as the superview to any views that you want it to manage, contrary to how &lt;code&gt;CAConstraintLayoutManager&lt;/code&gt; works.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A compilable and much more complicated example can be found &lt;a href=&quot;https://github.com/jweinberg/JWLayoutViews/blob/master/Classes/ConstraintLayoutTestViewController.m&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;</content>
 </entry>
 
 
</feed>