If you’ve ever worked with Xcode above version 5 you’ve probably come across something that is called auto-layout. You’ve probably noticed those Icons especially in the newest versions and you have probably stumbled across the term „constraint“ here and there. Those are incredibly important things to know when dealing with development in Apples Ecosystem and their devices. This Module is all about those things.
It will teach you to understand constraints and how they work, understand how to create and manage them inside of the interface builder or inside of code because those are not mutually exclusive and you can use them in both way. The Theory behind them however stays the same. It’ll teach you how to debug constraints inside of Code and the Interface Builder and also how to test for different screen sizes and what to focus on when testing constraints.
Or in short, this module focuses on how to create adapting layouts for your apps, like a responsive website.
The concepts in this module are a little bit more advanced and they can seem confusing and daunting at first. They require a little bit of theory here and there. That’s why we’ll dive into that first and then later we’re going to look at the practice. That’s why I chose to split this module. It’s important that you know the theory before you get into the execution and working with constraints because it’ll make everything make sense. The Theory section is quite small but ist is super important to understand. You have to understand all of that in order to debug constraints fast and easy and to create them fast and efficiently. The Theory part is what helps you understand what will come in the practice section and it also defines the terminology that you need to know.
The practice part is part where the fun stuff happens and luckily, much longer than the theory. If you’ve taken a look at the outline the practice part is a lot longer. While the theory is important, the real value of the auto-layout concept is in the application, because it helps you maintain a beautiful UI throughout all devices, screen sizes and size configurations.
Let’s just take a quick look at the outline of the Module before we get started.
First of we have the Theory part of the module in which we have some things we need to touch on before we can dive into the application. First things on the list there is the Canvas system on Apples devices and how apple manages constants. Next we’ll take a look at the problems we have with layouts. This will lead to the solutions that apple implemented. This is basically auto-layout with a special focus on constraints as the are the vital part of making auto-layout work.
The next section will be the practice section and it includes common tasks like stacking elements and tables. But this is just the introduction. We’ll dive very deep into working with constraints, creating and modifying them inside of the interface builder or using code. This is the very interesting part of the module. You’ll learn all the practical stuff of making auto-layouts works. But that’s not all because we also need to get into the cases if you layout doesn’t work as expected, that’S why I have created a complete lesson dedicated to debugging and finally we’ll do some testing to see if our auto-layout works.
Finally there is a section on bonus materials which is super valuable as well. If you purchased the extended access, this will all be available to you and I recommend checking that out as well. The bonus content includes a lesson on workflows and how to create layouts for existing apps or how to design and app from scratch. Also I have a Constraints Cheatsheet prepared which is a PDF that includes all the important information that we cover in this module. Lastly I included a recording of a workshop I did that focuses on dealign with auto-layout using some libraries, because apples auto-layout in code is not super easy to write and quite verbose, but there are some really great libraries that can help you make this more efficient and make working with constraints in code much easier.
So let’s get started!
So before we get started with learning Auto-Layout and Constraints and all that good stuff, there is something important that we should cover. It won’t take too long but it’ll make understanding Auto-Layout a lot easier, and that is bascially how the canvas works in iOS, macOS tvOS etc.
There were times when a pixel was used as a size measurement? For example you could say, make this view 200 pixels wide and 50 pixels tall. We didn’t need to worry about pixel density and all that stuff. Well, apple fixed that with the introduction of retina displays on the iPhones and macBooks. In the early days we could just tell the app to display an image 100 times 100 pixels and everything was good. Every device would display the image exactly the same way.
What happened when retina displays came along was that the image was rendered 100×100 pixels on an iPhone 4. On the iPhone 5, it was too, but it appeared only half as big on the screen as it did on the iPhone 4. That’s because the pixel density between the two devices was doubled. so Apple had increased the pixel density. Where 1 Pixel was on the iPhone 4, there suddenly were 4 on the iPhone 5.
In order to make an end to this mess, apple introduced the measurement using „points“ with Core Graphics. For us, this doesn’t change all that much. We just need to keep in the back of our mind that we don’t write the measurements in pixels, like the numbers you type in are not in pixels. They’re in points. So every time I reference a measurement in this module, it is in points, not in pixels. Don’t worry too much about it. It’s pretty much self explaining.
If you want to dive into the details however, there is a great graphic from PaintCode App that explains this in greater detail. You can find it in the lesson transcript below (right here.).
But that isn’t the only thing that is needed as a prerequisite for this module. There is something far more important. And that is how the canvas of the iOS vs the macOS is structured, because the have some similarities and some differences. Lets first look at the iOS canvas.
At first, the iOS canvas is a little counterintuitive to people, because it doesn’t reflect the way we learned cartesian-coordinates in school.
This is what it looks like.
Now, the point system on the iPhone is like a coordinate system like we learned in school. We have an X- and a Y-Axis, however the coordinate system is flipped on the X-Axis.
Both start in the top left corner, which therefore is the point (0,0). Ff you count the X-Coordinate up, you move along the X-Axis into the iPhones screen, the right in this case. The same happens with the Y-Axis, so as you increase the number, the coordinate moves down.
On macOS however, this is a little bit different.
Let’s just assume you look ash the window of a blank application. The point (0,0) is in the bottom left corner, whereas on the iPhone it was in the top left corner.
The X-Axis is still in the same direction, but the Y-Axis is now like on a common coordinate system, pointing upwards.
So if we would set the Y-Coordinate of a point to 20, we would move along the Y-Axis in an upward direction on the mac, while on the iPhone wo would move downwards.
This is all there is when it comes to prerequisites. Nothing more to be said then: keep this in mind for this module. It’ll help you understand certain tasks better.
Now, let’s dive into the topic.
Apple has a huge device palette. There’s iPhones and iPads in various sizes reaching from small to oversized and those devices can be used in Portrait or Landscape mode. Some of the devices, especially iPads even have a split view mode where you can use Apps side by side or you can use them as sidebars on iPads.
All of those variations were introduced by apple to create a seamless experience when using those apps. They wanted users to enjoy using the devices and that was only possible if the user didn’t get held back by lack of functionality. This was definitely a smart move and certainly it did make a lot of our experiences with apples ecosystem enjoyable because we can use the apps the way we want to.
The Thing is this made it much harder to develop apps because we now have to account for all the different screen sizes and size configurations.
So let’s just look at this example I’ve created. We have a login view of a fictional app right here. While on the iPhone 5 it looks fantastic, but as soon as we switch to iPhone 6 or 7, the login view just gets mashed up. The view doesn’t adapt to the screen size and therefore the login screen looks terrible on anything else than an iPhone 5.
Now how can we change that? Well, its not that straightforward by hand. Let’s just take this example of the login view to think about the problems we have. We could just check for the screen size in code every time the app gets launched and adjust the layout in code. And then every time the screen is rotated. And then every time the app is used in a sidebar view. And every time the app is used in split view mode, and so on. We could just go through all the different cases, create complex math functions that calculate the positions of the views and make the layout adapt every time some change occurs. This would cost us a lot of time to develop and would probably be really inefficient.
But there already is a much more elegant solution. The solution is Auto-Layout.
Think of a layout that knows how to behave. That can adapt to screen sizes without you having to write complex functions and calculating where a certain view should go.
Apple has implemented such a system into Xcode and all of the operating systems of the devices that unifies the system that makes up the layout and this is what we call Auto-Layout. Auto-Layout is similar across iOS and macOS and In fact, since you’re just using Xcode to develop for all those devices, there is no difference at all for you. The tools and menus look and work exactly the same on every project for every device and the rest is handled by the device itself.
Now, Auto-Layout unfortunately doesn’t work like that magically on its own. There is some work we need to do. We have to tell the auto-layout system how a layout should behave if changes occur, so it can react accordingly.
The thing we use to make this happen is called:
Now, I have good and bad news. Bad news first: Even though Auto-Layout is convenient and it works really well, we haven’t gotten rid of the complex math yet. That’s because Auto-Layout makes use of mathematical functions, called constraints, to determine the layout. So there still is quite a lot of math involved in determining the layout. Fortunately though, Auto-Layout is a system that is fully implemented by Apple, so we don’t even notice that 90% of the time.
So the good news is, even though we need to use complex math to make Auto-Layout possible, we don’t need to worry about it at all. We don’T need to know how to calculate the anchor points so that a view appears to be centered. We don’t need to implement interactions between to different wies to make them create margin around them. The Auto-Layout system takes care of that for us, so that we don’t have to, so we can take our time and energy and apply it to the things we are good at, like designing interfaces or building apps.
So, let’s take a quick look at how the constraints work.
Like I mentioned before, Auto-Layout uses mathematical equations to determine the size and position of the different views. Now to make this possible, each of those equations, each of those math equations describes certain aspects of the view – like for example the position, the height, the width etc.) and in order to work properly, the equations need to be structured in a way that those equations, when solved, have one and only one possible solution. They can’t be different solutions of that set of constraints. For example this means that there can’t ever be 2 constraints setting the X position of the view to two different positions. Or the height or the width. You can’t say this view is 30 points wide as well as 20 points wide. it’s obvious that this can’t work. If this would happen, auto-layout doesn’t know how to resolve the information and we get an error. Usually Xcode would tell us that or if it doesn’t, the app will just crash.
Because we have those mathematical equations, Auto-Layout can now determine how the layout should behave, when changes on the superviews size occur. That means, Auto-Layout can help us adapt the UI of apps to different screen sizes, make adjustments once the device is rotated or the app gets pushed into a sidebar. On Mac it would mean that we can react properly to window size changes. All of this is stuff that happens on a frequent basis. You shouldn’t ever have an app that can’t adapt to size changes or important elements of your layout could get pushed outside of the screen.
Lastly, because constraints are just math equations, we can easily use those to connect them to code. That is especially useful, when we want to make use of the constraints to reposition objects while the application runs for example. Constraints come in very handy when we get into animations for our apps. For example: We can make use of the X position constraints to create an animation, where the view moves across the apps screen or the Y-Position to make a view fly into a launch screen from the top. This is for example something I have used for an onboarding for an app I did a couple of weeks back.
Constraints – Theory
You now know what Constraints are and what they do, so we’re going to dive in a bit deeper how the constraints work in theory and how they are defined and where they can be „placed“.
There are basically two separate places you can use to create, set and work with constraints. First and foremost, there’s the Interface Builder. This is the obvious choice when you get started with constraints because it gives you a nice visual representation of what’s going on. But that’s not the only possible place to work with constraints, you can obviously also make use of them in code. We’ll take a look at that later in this section, as It helps to understand the basic theory in visual form first because the code gets more abstract and it helps to have seen and experienced the concept inside of the Interface Builder.
Now there is one thing left to note. There are different types of constraints and different places on a view that the constraints can effect. I’ll tell you exactly which constrains there are and which effect they can have, because it’s not exactly a mix and match type of thing. There are some rules that you need to follow in order to make this work, but don’t worry it is not as complicated as it sounds.
First of let’s get into the types of constraints.
Types of Constraints
Let’s just take a look at the most straightforward constraints that there are, which would be:
These constraints are really simple. Obviously, height and width define the size of the view. Top, bottom, left and right are there to define the position, based on the space that is measured from the top, bottom, left or right of the views „alignment rectangle“, which if you don’t know what that is, no worries we’ll get into that later in this lesson. In our case, the alignment rectangle is exactly the view itself.
But there’s more. Let’s take a look at another couple of constraints that you could set.
Now leading and trailing sound pretty straightforwardforward, but if you look back, we already have a left and right constraint, so the seem redundant. Well the difference is that the leading and training constraints define how the layout appears based on the fact if it’s a left-to-right language or a right-to-left language. So it’s especially important if you’re dealign with text. In most languages like english, german and so on, the leading edge is the left edge of the view and the trailing edge would be the right edge of the view, while as for example in hebrew or arabic type languages you would have both of those flipped, so the leading edge would be the right edge and the training edge would be the left edge.
That’s it to the leading and the trailing edges. Now we have another constraint that helps us to position our view more accurately. Those are the centers in X and in Y position. This is really handy because usually you’ll want to align content based on its edges or on its center. If you want to align something to the center, those are the constraints you’d want to use, because they act as if they were in the center of the view.
The next ones again focus on text. The direction is not important in this case but before I can explain what they do, we’ll need to have a super short typography lesson. What I’m going to tell you is what the baseline is. In our case right here you can already see what the baseline is. The baseline is the line on which we have all of our letters sit on.
This is super important because most of the time if you’re dealign with multi column layouts for text for example, you’d want the baselines to align to create a great reading experience. And there’s 2 ways to go about this, because there are two types of baseline constraints. The first one is the first baseline and the second one the second baseline.
Think of a multi line text field. The last baseline would be the baseline of the last line of text, while the first baseline would obviously be the baseline of the first line of text.
Now there are only a couple of constraint types left. Let’s look at those.
- Left/Right/Top/Bottom/Leading/Trailing Margin
- Center X/Y With Margins
If you’ve worked with css before, you most likely know what margin is. If you haven’t, no problem. Let me just explain. Imagine a UIView you just put in your project. I’ll reference this view as the „superview“. This UIView has a boundary around the edges of the view. Now if you want to nest a different view inside of this one, you most likely want to arrange it inside the view in some way.
If you’ve worked with interface builder before, you’ll have noticed that views that are nested inside of another view will snap to a helper grid. For example if you move one of the nested views in your superview to the edge, you’ll notice that it will snap close to the edge of the view, but not exactly to the outside boundary. There is a little bit of space. It basically gives the view a little bit of „space to breathe“ in the superview. That little bit of extra space is what is call margin.
Let’s just look at an example in Xcode to make this more tangible.
To create layouts that look great and don’t feel too cluttered, you’ll need this margin a lot. In the Interface builder, the margin is not as apparent as in code because you’ll work with it quite naturally, but still this is something you need to think about.
Don’t worry though if you’re unsure about the concept. We’re going to take a look at this again in the practice section here and there so that I can make sure you fully understand what this concept means and how it works.
So let’s talk about what the alignment rectangle is. I mentioned it before and now we’re going to dive into that.
If we talk about an alignment rectangle, we talk about the boundary that surround a view. It is essentially the boundary that snaps to the helper grid in the Interface Builder. It is apparent when dealign with a blank view inside of the Interface Builder because the alignment rectangle is pretty clear there.
But there are cases where the alignment rectangle in fact isn’t as apparent as when using a view. Imagine for example a label of text. The alignment rectangle is not directly visible, but it is still there and is still something you need to worry about.
Let’s just take a quick peek inside of Xcode to see what I’m talking about and then move on.
Anatomy of a Constraint
You now have a complete understanding of what types of constraints there are in the auto-layout framework. But that’s not all there is. What I haven’t told you yet, is what exactly a constraint looks like.
I told you before that – under the hood – constraints are math equations. But right now we don’t see a lot of that. Actually we have never seen any type of equation in this sense at all. So, let’s fix this.
Constraints are equations. What do equations need? They need parameters. Just like most functions, there is a set of varying numbers that define the equation. In code these parameters are passed with the use of function arguments. But right now let’s go the little more abstract route, because we can visualize the equation in a way that is much easier to understand.
Apple hast a great way of visualizing the „Anatomy of a Constraint“ in it’s documentation, and I’m going to use this example to explain what’s going on.
Let’s take an example. The constraint should look like this.
What you can see here, is exactly how constraints are calculated. Now because this can be a little overwhelming at first, let me break it down for you.
Firstly there is to note that each Constraint is usually a relation between two views. A constraint can however exist on just a single view as well. Most of the time though, a constraint is an interaction between two different views and how they behave. So the equation features two view objects. The red view and the blue view in our example right here. Those are the views that we want to create a behavior between.
Also we have two attributes. Those are the attributes of the views that we’ll use to adjust the views according to the superview. For example you’ll need to specify, which places on the view the constraint need to be applied to. In our case here this is the left and the right boundary of the corresponding views alignment rectangle. So the redView.left which means we take the left edge of the red view and the blueView.right because we want to take the right edge of the blue view.
If you now set the constraint to the left side of a view, for example the red one, it usually is equal with the constraint on the right side of the view on the left, our blue one in this case. This relation is represented by the equals operator in the equation. There are also other types of relations like more-or-equal as well as less-or-equal, however I’ll get to those in one of the examples, because this si a little more difficult to explain.
Multiplier and Constant
The last thing we need in this equation are the multiplier and the constant. The Constant is very straightforward. This is a value that just gets added to the value of the constraint. For example if our views in this case here would align perfectly on the sides, that would mean there would be no gap between them. In order to introduce a gap of 8 points between the two views, we would enter a constant of 8 here.
Another example: Let’s assume that the blue view is bound to the left margin of the view it is nested inside, we would already have a margin of 8 if the left margin of the superview is 8. However this would not be reflected inside of our sintraint because we are using the margin of the blueView. If we wanted to increase the gap to 16 on the left side, we could use the constant and add 8 which would result in a sum of 16, or we could use the multiplier and multiply the value of the superviews left margin by 2. Our constant would remain 0 in this case.
Combination Of Constraints
Like I noted before, a proper set of constraints is one that has one and only one possible solution. For that to be possible we have to think about how to arrange the types of constraints in a way that leaves us with only one possible solution. This is easier to understand if we look at the attributes of the view that can be adjusted by a constraint.
All that a constraint can do is move the view around and change its size. That’s essentially all the information it needs to work.
So a proper set of constraints sets:
- the size
- and the position
The only restriction in this case is that there can’t be constraints that conflict each other. But we’ll take a look at that later.
The last thing that can influence constraints are priorities. This is pretty easy to explain, because priorities are numbers ranging from 1 up to 1.000, with 1.000 being a required constraint (meaning that the app will crash if the constraint can’t be resolved) and 1 to 999 being different levels of priority for resolving. This is interesting for example if we have two conflicting constraints. If both of the constraints have the priority of 1.000 (required), the app will crash. If one of them has a lower priority, the other constraint will be executed correctly and then the one with the lower priority will be ignored. If we have two conflicting constraints with less than 1.000 priority, the constraint system will execute the first one as good as it can and then move on to the next one. This means that if the constraint can’t be met 100% the app will not crash and the constraint system will try to get as close as possible and then move on.
So, this concludes the theory part of the auto-layout module. I know this is a weird and complex seeming concept at first, but to be honest I can not imagine having a more flexible and intuitive way to handle layouts than this. Once you wrap your head around this, it becomes second nature to you and you’ll never want to go back to any other system, I promise you!
Next we’re going to dive into some practice and apply this knowledge to an example. But before we put all of this constraint knowledge this into action, let’s just look at a way to create layout without the use of constraints to get used to the interface builder.
If you’ve ever created layouts or designed any apps, you probably came across a couple of common tasks that you needed to perform. For example, a login form with a label and a text box stacked on top of each other, the same again and finally a login button just like what a normal login form would look like. Not that those are very time intensive layouts, but still it would be nice to save at least some time on those everyday tasks.
Well, Apple came up with a clever idea to streamline common tasks like this. There is a set of different views to streamline the process of those common tasks. And you don’t even need constraints to get started. Or at least very little.
The first thing that I want to show you that makes your life much easier, are stack views. I just described the picture of this login view with those stacked views, all the same width etc. This is exactly what a stack view can do for you.
But I don’t want to go into too much boring theory, let’s just look at them in action right in the Interface Builder.
There even is a button inside of Xcode that wraps all the selected elements inside of a stack view.
Another super handy thing to have is the TableView. Like the name says, a TableView is a view that presents information in a table like way. You’ve probably seen them plenty of times as they are one of the most commonly used presentation options in iOS and macOS development. Now they don’t exactly have something to do with auto-layout because the superview will still need adjustment to match the screen size, but what is interesting in this case is that the table view arranges its items stacked on top of each other much like a stack view. Also it makes use of the scroll view on its own, so you don’t have to implement a scroll view yourself.
Again, let’s look at a little example.
Lastly I want to focus your attention on the CollectionView. The collection view is a little more interesting than the table view when it comes to auto-layout. The CollectionView presents elements just like the tableView, with one special difference. The Information is not presented in a table, but rather in multiple little squares. Those buttons can take any size that they want – height or width – while on the table view, it was just possible to change the height while the width was always limited to being exactly the width of the tableView.
This is the last one of the views that I wanted to show you, but before we move on to the constraints, let’s just take a look again, what this would look like in the Interface Builder.
Now, those are very effective ways of creating layouts without having to deal with constraints too much. Most of the work is done by the Framework itself, but still this doesn’t help us as much as we would need to create a fully adapting layout. Also they are not too customizable, so as soon as our layout gets a little bit more complicated and sophisticated, we will need more flexibility in our layout.
So you can see, there really is no getting around this time. We need to get into constraints to finally make our apps beautiful and make them adapt to any screen size.
Constraints – Practice
So let’s dive into the meat of the whole module. We’ve nailed the whole theory by now and you know what to expect from a theory standpoint. Constraints are the part that make the App adapt to layout changes and they are the part that creates the magic in our apps.
From a technical standpoint, you know what’s coming. However what we haven’T looked at is how the implementation is handled.
Basically there are two ways to make use of constraints in your Xcode projects. You have the option to create them inside of the Interface Builder, or you could make use of the constraints by defining and modifying them in code.
They don’t have to be mutually exclusive, but it helps to decide on one approach and stick to it because otherwise it’s hard to keep track of what’s happening in your layout. There might be some bugs awaiting if you ignore this fact.
Let me just state here that I don’t see any issue in mixing the two concepts if you take a couple of things into consideration. For example, I recommend you define the constraints in Interface Builder. We as humans rely greatly on our visual sense to collect information and the Interface Builder has some excellent ways to visualize the constraints and make them easy to grasp and understand.
On the other hand, there are some things that need to be done in code – for example when dealing with animations – and there is no way around connecting and modifying them in code. So my recommendation when you’re just starting out with auto-layout, is to only make use of the code to modify constraints in the beginning.
The visual way of creating constraints inside of the interface builder helps understand whats going on. However if your apps get more complex or you work on projects with multiple team members, handling merges on git can become painful. That’s usually when you would want to switch to code entirely, but right in the beginning the interface builder is the way to go as it makes grasping the concepts super easy.
So in summary:
- Create constraints using the Interface Builder
- Modify constraints at runtime using code
Now that we’ve got that out of the way, let’s dive into the Interface Builder.
The Interface Builder is the encouraged way to create and adjust constraints. There are plenty of tools and mechanisms that make dealing with constraints as easy as possible. There are ways to create, modify, debug and test constraints in Interface Builder that I’ve personally come to fall in love with. At first I was intimidated by all the different context menus and I had no idea what I was doing but since I’ve got the hang of it, I can’t ever imagine giving this up. Apple has built some great tools to make working with constraints easy and effortless.
Let’s open up Xcode and take a look at everything important when dealing with constraints.
- Creating Constraints
- Updating Views
- Finding & Adjusting Constraints
- Fixing Errors
- Connecting Constraints to Code
Creating Constraints in Interface Builder
Let’s practice Constraints on our login screen example that we’ve used before. First thing I want to do is place a nice logo inside the view.
Now there are two common ways to create constraints in Xcode. The first one is to click-and-control drag the selected view to the superview that the constraints should be applied to. The Direction in which you drag is important here and will define if for example the centering option will be shown vertically or horizontally. Let’s just center this image vertically and horizontally on the canvas to see how this works.
This method is very intuitive and does lead to the goal pretty quickly. All you have to be aware of, is the fact that all the information you provide have to lead to a set of constraints that can be resolved properly. If you don’t remember them exactly, the were:
- Set size of the view
- Set the position of the view
- X Coordinate
- Y Coordinate
I generally don’t use this method very often. Sometimes there are very small margins or sometimes you miss the right view. There can be a couple of problems with this approach, but I wanted to let you know this method exists either way. Maybe you’ll like it more than the second one, I’m about to show you.
My preferred method of adding constraints to a view are the add constraint and align menu. You can find them right here in the footer of the Storyboard. We already have the constraints applied to the logo view right here, but let’s suppose you did something wrong and you want to reset all the constraints on this view. Here’ how you can do it.
You can reset all the constraints on the selected view right here or you could reset all the constraints on all the views in this container.
Let’s just reset all the constraints on this selected view – you have to make sure the right view is selected – and re-add them using the other menus just so you can see how the workflows differ.
Sometimes you’ll get some yellow lines inside of the Storyboard. That usually means that the layout that is displayed to you on the screen right there is not matching the one that will be displayed once the app is run.
There is a method do align those again to make sure „what you see is what you get“. Just choose Update Views in the Menu or use the Shortcut alt-cmd-= to align the view properly.
If you followed along, you can run the app again and you’ll see that the constraints are doing their magic. They take care of the alignment of the logo just like we told them to. Basically this is the starting point to any other layout. The process is exactly the same and can just be adjusted to fit any needs. But there are many more details.
So the constraints are set now. But what if you’re not happy with the result they are producing? Maybe you want the logo to be offset from the center to the top? You can easily adjust the values of the constraints using the interface builder. Again there are multiple places you can choose to do that.
First of, you probably noticed that there now is a Constraints item in the sidebar – the outline view – of your apps views. Right there you can select and adjust the constraints in the sidebar on the righthand side of the storyboard. If it’s hidden, just click the sidebar button in the top right corner to uncollapse the sidebar. The part that is interesting to us is the constant part. This is where we can enter any number – this value is defined in „points“ – to offset the constraint by the entered value. Let’s try it now.
This process has the downside that you’ll have to deal with the constantly growing number of constraints in the constraint Item in the sidebar. Since all constraints are grouped in there this can get messy. Isn’t it much more convenient to just select the item that the constraint is applied to and find the corresponding constraint in there?
I guess that’s what the apple developer thought too, so they created the size inspector view in a way that lists out all the applied constraints on a selected view.
As you can see this is a much more convenient way to see constraints and it just lists out all the constraints that are relevant for this view. Hovering over the constraints in this list Highlights them in the Storyboard if possible and you can easily edit them using the „Edit“ button. Or you could use the graphic above to select the constraint you want to focus on.
Let’s try to adjust the X position of our logo with those controls to see how they work.
Interface Builder Canvas
Another way you can see and select constraints is the Storyboard Canvas itself. Right here in the menu you can find the option to show the constraints on the canvas just by selecting Editor -> Canvas -> Show Constraints. Obviously this option does not present you with all the constraints that there are, but only with the onces that correspond to the selected view. It does this so you don’t get overwhelmed by the incredible amount of constraints that will be in your project as it grows and becomes more complex.
From Interface Builder to Code
Now that all the constraints are set and our views align nicely, we can now go into the coding section where we’re going to focus on how we manipulate the constraints with code. Also I’m going to show you how you could also create constraints using code although this is not something that I recommend when starting out, since the constraints get much harder to maintain and debug. However if your working with other people on the same project it soon becomes necessary to only work with views inside of code because for example if you’re dealing with git you can resolve merge conflict much much easier. In the beginning however I recommend you use the Interface Builder to practice Auto-Layout because the visual components make understanding it much easier and this knowledge will serve you well later when you start to only use code.
Before we can deal with the constraints in code however, we need to have constraints to work with. Firstly I’m going to show you how you can connect your existing constraints to the code files via an @IBOutlet and then later we’ll dive into the creating constraints with code without making use of the Interface Builder.
Let’s connect an existing constraint to code for now. We’re going to take the center X constraint from our logo and connect it to code so we can set it during runtime. For this to see it take action we’re going to implement a button at the bottom of the page that will set the constraint to a new value.
We’re first going to place the button just below the logo, assign constraints to it, so we can see if all the time on all devices and connect the action from the button to our code.
To be able to do that I’m just going to switch the view from the standard editor to the assistant editor and select the file that should be displayed in the assistant editor.
Now let’s do the same thing with the constraint. Find the Constraint you want to work with in the outline view of your scene and select it. Now control-drag it into the assistant editor and let go. You can give the variable a name and viola, the constraint is connected to code. It works just like with any other object in your view.
The Only thing that is left to do now is to increase the constant of the connected constraint when the button is pushed. Finally, you can run the app.
You might encounter some cases where you need to create and manipulate constraints directly in code. In this case there are much less tools involved and also we covered the behavior of constraints in the Interface Builder part of the exercise so this part will most likely end up smaller than the Interface Builder part. However , there are some additional things you need to know about.
Here’s what I’ll focus your attention on:
First of we’ll take a look at the required objects and the required functions for creating constraints in code. After that we’ll take a look at how to adjust constraints.
We’ll focus first on how to create Constraints in Code.
Creating Constraints in Code
Just like with the constraints we dealt with in Interface Builder, there are a couple of things that need to be set in order for the constraints to work properly. The concept is exactly the same so a valid set of constraints defines the size of the view as well as the position of the view. So just like the rules we had before ein the interface builder. We need to set the width, the height and the X and Y Coordinates of the view.
So we need to create some variables that contain our constraints. The types of constraints may vary from situation to situation, but let’s just say we want to replicate the logo example by creating the constraints in code this time.
A little bit of work is needed to set up the testing environment in this case. Let’s just remove all our constraints we added in the interface builder and remove all the outlets for constraints. We’re now at a starting point where everything should be like we just pulled out the view of the object library and put it on the canvas.
Now we need to create an outlet for the view from the storyboard to the code file. Of course you could also create the view inside of the code file and ignore the interface builder completely but I’ll focus on that in another module since there is a lot to cover here too. This is the first object that is required to create constraints in code. I’ll refer to this as the „imageView“ in this section because we’re later going to put an image into this view as it should display our logo.
The second object that is needed is the „superview“, meaning the other view that our „imageView“ is nested inside. This is necessary because swift needs to know the two objects that the constraints exist between. You can never connect a constraint to nothing, it always needs a first and a second object to work with. There are some special cases where the second object is not interesting for us for example if we set the width or the height of a view, but I’ll cover that later. Just know that there are some exceptions to this rule.
The last object we need is the constraint itself. Constraints are created as a NSLayoutConstraint object which is part of the UIKit. You can just create variables of that type and save the constraints inside of there. What’t more interesting though is the constructor you’ll need.
I’ll classify this as a function since a constructor is basically a function call that initializes the state of the object. There are just two versions for the NSLayoutConstraint. The first one is empty and creates an empty constraint which basically does nothing at all. The other one is the interesting one. Let’s look at the required arguments for this constructor call:
First up we have an Item. Then we have an attribute, we have relatedBy we have a toItem another attribute and all of this is followed by the multiplier as well as a constant.
If you payed attention in the theory part, you might notice something right here. That graphic I showed you that specified the anatomy of a constraint basically has exactly the same structure that the arguments in this constructor call have. This makes it quite easy to understand what is happening here and this is the reason I taught you the anatomy of a constraint first.
Firstly we select and item. This is the object that should be aligned or adjusted based on the constraint. The attribute specifies which value needs to be set. Remember this could be position or size related or even both.
Then there is the relation. Most of the time you’ll be looking at equals, but for example if you want something to expand only to a certain width, you could use a more-or-equal / less-orequal relation.
Then there is the toItem which is the item the value will be taken from and the attribute which acts just like the attribute on the first item.
Lastly we have the multiplier and then the constant. Both of them should be familiar to you from the Interface Builder screen.
You might have noticed, that there are some cases in which you don’t need all the parameters in the function. Especially when setting the width or height of a view, you don’t need to have a superview, because t just affect one view. But the arguments in the function are required, so what can we do?
Apple has a clever way of dealing with this. If you’re familiar with optionals in swift, you might know where this is going. Let’s just say we want to set the height of a view with the name of „view“. We would enter „view“ as the item and „Height“ as a parameter. In our case let’s just say we use the equals relation.
Now what about the toItem and the attribute of the toItem? Easy. As our toItem, just set „nil“. Now the interesting part is the attribute. This is where we will enter „notAnAttribute“. This is a case of an enum that is defined as 0, meaning this will not affect our layout equation in any way. We can now use the constant to set the height of our view.
Sounds a little bit weird at first, but that’s just something you need to keep in mind to work with it.
So you now know all the attributes, items, equations and everything in between. But how do we tell this to the auto-layout system? This is hard to explain using slides, so we’re just going to jump right into Xcode to get this working.
Sample of the most common Functions
You probably noticed that all of this seems a bit complex and confusing and the especially the creation of constraints in code is very verbose. That’s why I created some bonus content about a Library that can help you manage constraints with more ease.
I’ve talked about it before, but just as a reminder: Constraints are handled as math equations that should only have one and only one possible solution. Sometimes however we make mistakes when constructing them, leaving us with problems, meaning: multiple or not even a single solution to our equations.
We need to be able to identify these problems and solve them properly. That’s exactly what I want to focus this section on.
Types of Errors
Again, like before, I want to introduce you to a little bit to theory first before we dive into solving auto layout issues. Because there are 3 different types of issues that can occur:
- Unsatisfiable Layouts
- Ambiguous Layouts
- Logical Errors
Let’s dive into each of them on its own and I’ll show you exactly what they mean as well as how you can solve them.
First up, there’s Unsatisfiable Layouts. Those are layouts that have no valid solution at all. The problem here is that you might have two constraints that conflict each other, because they can not be true at the same time. You can think of this in a very simple way.
Say we have a view. We have already set a constraint that the views height should be 20. Now if we add a constraint to the view that tells it to be 30 in height, we have an unsatisfiable Layout. The layout can not be solved because there obviously is no solution to making a view 20 and 30 point in height.
- Height of view: 20
- Height of view: 30
So that’s the first problem, the second one is ambiguous layouts. This happens when a layout has two or more possible solutions. This usually happens when auto-layout hasn’t got all the information it needs to solve the layout completely. This would mean that one attribute is not properly defined or that the system has conflicting optionals constraints with the same priority. Both of those cases create a system that can not be solved.
Think of another example: We have a similar view as before and we nest this view inside of another view. Now we set the top and bottom boundaries to be the ones from the superview with a constant of 20. Also we set the superview to be 120 in height. That leaves us with a view that is 80 point high and has a clearly defined X-Position. What this doesn’t have is a set Y position and a width. Even if one of those would be solved we would still have an ambiguous layout because the auto-layout system can not decide where to put the view or how wide it should be.
The last two errors are some that Xcode can help with. There are tools in the Interface Builder that can help manage those errors, find out what’s going wrong and resolve some of the issues. But there is another type of error that unfortunately Xcode can’t help with.
Apple calls them logical errors and frankly that’s exactly what they are. Some people would also call them bugs, because these are issues that can’t be traced back to math. It’s just setting constraints in a way that doesn’t reflect the way constraints work. It usually happens when you have false assumptions about how auto-layout works and set constraints in a senseless way.
Most of the time this happens when dealign with constraints in code, which is another reason I recommend using the Interface Builder when your just starting out.
Now let’s look at all of this theory in action when we use Xcode.
Let’s just create a view in the interface builder as a superview and a view nested inside of the superview. We’re going to set constraints in a way that matches one of our errors. That way I can show you how the tools in the Interface Builder can help us solve our issues.
Right in the top left corner we can see a red or yellow arrow that tells us that we have some issue in our auto-layout constraints. Let’s just go ahead and click that to see what the problem is and what Xcode tells us to do to solve the issue.
As you’ve seen we can have Xcode help us with the constraints quite a bit, but sometimes the messages that Xcode gives us are not super helpful. In this case it is important to know which information Xcode actually needs to resolve an auto-layout properly. We have done that well in the exercises before but I didn’t really tell you the nuts and bolts of it.
It might be obvious, but auto-layout needs 4 informations to layout a view correctly, otherwise you’ll have an ambiguous layout right in front of you.
Those properties are:
- X Position
- Y Position
Those informations can be provided in a variety of ways. For example you could set the width of a button by giving it a fixed width constraint, or you could make use of the leading and trailing properties in correspondence to the outside of the superview to give auto-layout the possibility to make the width of the button variable. Both have different results in the app itself, but what they have in common, is that they determine wich width the button should have.
So when you’re debugging your constraints, just remember to provide all those attributes.
There’s not that much to say about testing. Just a couple of facts to keep ing mind. I want to keep this section short and then leave you into the world with all your new skills so you can get to work on your project.
Luckily, Xcode 8 introduced a bunch of new features that can help you create and maintain beautiful layouts so you don’t have to worry about that all too much. Now there are also some tools that allow you to test your layouts inside of Xcode. We’ve seen it before but I want to dress them quickly. This basically is the live preview of your layout with constraints and makes debugging the constraints a little bit easier if you choose to create the layout using the Interface Builder. If you get more advanced and work with teams you most likely will not be working in interface builder anymore but like I said, for practicing purposes the Interface Builder is just a great tool.
Finally I want to make you aware of the fact that even though this is a live preview, this doesn’t mean that everything works as well on a real device or the simulator as it does in the live preview.
I’d recommend when building a layout to test it every once in a while inside of the simulator or even better on a real device. Nothing beats living the experience that someone else might too on their device. Put yourself in your users shoes and test as much as you can on different devices and device sizes.
That’s all I have for you in this module. If you purchased the bonus content of this module as well make sure to check it out.
Either way, note that it is crucial with this topic that you practice this stuff so that it will find its way into your workflow naturally. There will be this project when you think: „What wasn’t there a clever way to create adaptable layouts?“ and you’ll remember everything from this module. If you don’t remember don’t worry. These videos don’t go away. You can watch them as often as you like and you can go through everything again and again and that’s what I encourage you to do!
Also I have appended the whole transcript of the module in text right below the lessons, so if you look for something special, just use the search function in your browser in the specific lesson or view the full transcript and search in there.
As a practice I’d recommend you try to build the login screen example we’ve been creating in this module. If you’ve done that, there is another exercise that I’ll append into the bonus content that will help build understanding for creating layouts that might not be that obvious at first. But don’t get frustrated if this is giving you a hard time. Spend some time and you can come up with the solution. After you’ve created the layout yourself or if you’re stuck, you can watch the solution video that will show you how I solved the problem.
This is an excellent opportunity to test your knowledge and practice thinking outside-the-box with auto-layout.
It’s now up to you to apply this knowledge. Practice and get better and I promise you won’t regret learning auto-layout because it is an amazing concept!
That’s all I have for you in this module.
Now, Happy Coding