Join Simon Allardice for an in-depth discussion in this video Exploring Auto Layout, part of Cocoa Essential Training.
In 2011 Apple released AutoLayout, a new method for how Cocoa user interfaces arrange and resize and lay themselves out. Now AutoLayout replaces the older technique called Struts and Springs, which is still currently what you used in iOS development. And with Xcode 4.3, AutoLayout became the default layout method for Cocoa projects. And I am in 4.4 now, and it's what we are going to be using in this course. I won't be talking about the older Struts and Springs methods. Now we have been using AutoLayout already, and a lot of the time it just works.
It's worthwhile to know a little bit more about what's going on. So I have just created a new out-of- the-box Cocoa application, haven't done anything to it yet. I am going to drag on a button or two. Now we have seen the guidelines that appear when you do this. And let me tell you that AutoLayout is not at all about these guidelines, and it's not really even about the button, it's about what happens when you let go. We see the guidelines here on the left and on the top, the dotted blue lines, but if I let go you'll see another couple of lines appear, in this case to the top and to the left. This is what AutoLayout is all about.
These are what are referred to as Constraints. And Constraints describe a relationship between two visual elements, two views, like the relationship between the button and the top of the window here or the relationship between the button and the left-hand side of the window. If I click on the button over here on the right, I see two different constraints again to the top but this time to the right. As I'm dragging on different elements onto the page, different constraints are added depending on which part of the window that I put them on.
Oftentimes those constraints are based on say the right-hand or left-hand side of the window, but if I'm trying to arrange buttons beside each other, say down here, for example, I will also get constraints between the user interface elements themselves. So this selected button doesn't have a constraint to the right-hand side of the window, but it does have a constraint to the button next to it. And depending on the circumstance, a constraint might try and keep things together or keep things apart or both at the same time, in this case keep these buttons close but never allow them to touch.
Well, Constraints aren't actual objects and Cocoa, it's the NSLayout constraint object. They are added by Interface Builder as we edit our XIB files. So if you click any of the objects, whether they are buttons or any other kind of user interface elements, you'll then see the constraints that affect that object. For this one now I have three constraints, the right-hand, the bottom, and the one to the next button. You can then actually click any one of these constraints. Sometimes they are a little difficult to grab hold of, but you can usually manage.
When you click that constraint, you'll see an amber highlight that will show you what objects that constraint affects, so this one between the two affects these two buttons, this constraint just affects this button. Now as a side note it's a common mistake for new Cocoa developers to accidentally have a constraint selected when they think they have a button or some other element selected. So if you see the amber highlight, know that you have a constraint selected, you don't want to be trying to Ctrl-drag from a constraint to a code file. When buttons are properly selected they should be blue.
You can also get to constraints from the expanded Dock view. So here, for example, inside the Main view I can see the different constraints I have and actually take turns and selecting different ones vertical space, horizontal space, and so on. These are true objects. With any one of them selected, I actually have elements in the Attributes Inspector that I can affect, and we'll see this in a moment. Now most of the time you don't add constraint yourself, you just let Xcode do it. But occasionally you can, occasionally it's needed and worthwhile.
As I am dragging on elements, Xcode makes a pretty good guess of where the constraints should be, whether that's dragging them on for the first time-- in this case it's choosing to add constraints to the left and to the bottom--or if I move things around, say up to the center here it's going to add two constraints, this one which is making it a center constraint, and this one which is tying it to the top. So you can feel free to rearrange the object, Xcode will rearrange the constraints for you. I have added nothing but buttons right now so I am going to grab a couple of other things here, and let's grab a Layout view.
I am just going to drag on a Tab view here. And drag that wide allowing the guidelines to give me suggestions for where it should be positioned, but noting that with this Tab view selected I have multiple constraints here, to the left and to the right, to the bottom, and you know there is a constraint above that button, and there is a constraint below the button here. It's interesting often to see how Xcode rewrites this as you are editing it. If I delete that button and select the Tab view again, we'll see now the constraint that's focused is really this one over here.
And as I keep on going adding different things, say a pop-up button over here on the left and deleting the button on the right, we'll see a different kind of focus going on. Sometimes it will take you a bit of rearranging if you want to get the constraints back to where you thought they should be. And the guidelines can be very useful for that. In this case I rearranged it a little bit to make sure that there was a constraint between the Tab view and the button above it.
And we'll get more into rearranging some of these in a minute. So I am going to go ahead and run this just with Command+R. As we'll see in a moment, we don't actually even need to run this application to see the impact of AutoLayout, because it works in the Interface Builder view. But as I resize this, it's actually looking pretty good. The Tab view is expanding both horizontally and vertically, the buttons at the bottom right are keeping together the way they should. Although if I start to collapse it a bit, we are getting some impact we probably don't want, so we'll see how to fix that a bit. Quit out of that and back into Xcode here.
Well, first, I am going to rename a couple of things because it's important to understand how Xcode is going to work with this. I will rename this button down at the bottom left to Import..., which will make the button a little bit wider, but because of the constraints it will still be fixed on the left-hand side. On the other side, if I change this button to the words OK, take a look at the button to the left of it. The OK button will collapse, and this one will move to the right based on the constraint that's written there. Essentially what's happening is what you would hope would happen, and most of the time it just works.
So we don't have to actually run the application, as even in design view we can see the impacts of the decisions that we are making here. One of the problems is that entire Tab view is collapsing, which is not something that I really want. How can I fix this? Well, we are going to add a manual constraint. I am going to select this Tab view, making sure that it's highlighted, and I could double-check that in the Jump bar or in the Dock. And then go up to the Editor section, and what we are interested in is the Pin menu, this is where most of your manual constraints can be added.
I want to stop this from shrinking too much when we move it up vertically. So I'm going to give it a specific minimum height. So I will say Pin > Height, and it adds into this constraint and selects it for me. And right now this is set to a height constraint of being equal to 240; it has to be equal to 240. That's not what I want, which is fine. I can change that. I just don't want to get too small, so I am going to say it should be greater than or equal to 100.
I don't care if it's more than that, but it shouldn't be any less. I will go ahead and hit Command+R just to see this running. We can continue to resize, we can drag this wider but as I make it shrink I can't make it close anymore than that because it's actually now staying at 100, that's the minimum size. We're still having problems this way, though. It's collapsing too much. Well, I could do another fixed width constraint, perhaps even based on say the button width to make sure that these ones don't collapse too much, but that's a bad idea.
In fact, as much as we possibly can we want to avoid any fixed numbers. Because say if I go ahead and localize or internationalize this application, I might automatically have the text on these buttons changing and being replaced with different amounts of text based on the culture settings of the operating system that user is running this App on. So I don't know exactly how wide these buttons will always be. Plus, more than that, I don't want to have to stop measuring the width of my buttons. I really would just like the Import and the Cancel button to maintain a good distance from each other.
But what is that distance? Is that 20 pixels or 40 pixels? What might it be on perhaps a Retina display versus a normal display? Well, I don't care, and I don't want to have to think about that, luckily I don't have to. I am going to add another constraint, and I am going to do that by first selecting both buttons. So select the Import one, then the Command-click the Cancel one. We have both buttons and nothing else selected. Up to the Editor menu, down to Pin, and this time what I'm interested in is the Horizontal Spacing, though again, I am going to have to tweak it a little bit.
We add that, and we get a new constraint. The constraint is selected. I have the amber outline, telling me which two object this affects. What it's saying right now is this need to be equal to 229. That's not what I want. Again I want just a minimum size. I want some kind of distance between the two. So I want a greater than situation going on here, and it's asking well do you want a greater than 229, well no, I don't. Now I could put in something like 20 or 15, what's a better idea here is that I just click standard, and that makes it automatic.
I'm telling AutoLayout you go figure it out based on your own internal rules. So go ahead and Command+R with this one, now we drag it wider we get the interface resizing itself correctly, if I move it up towards the top we have the minimum height of the Tab view, and as we close here we see that the buttons get the perfect distance from each other and don't get any closer. Very flexible. AutoLayouts are great way to allows us to easily create apps than in other environments would often require writing code to handle window resizing and measuring the relative distance between objects.
Now this is just an introduction. It can get more complicated than that. One thing to be aware to be aware of is that all constraints--and I have one selected here--have priorities, which by default begin at 1,000. Sometimes you can get some worthwhile behavior by having different constraints with different priorities. Now that's beyond what we need to do in this course. So take a look at Apple's documentation on AutoLayout for more on that.
- Installing the tools
- Creating your first app
- Adding basic interactions
- Understanding the Cocoa application life cycle
- Creating custom controller classes
- Creating alerts
- Understanding delegation
- Working with buttons, text fields, sliders, and more
- Using layout and data views
- Adding and editing toolbars
- Using key-value coding
- Binding objects
- Debugging code
- Distributing an application
- Creating icons and full-screen apps