Tools • iOS, OS X • 54:36
Auto Layout’s powerful constraint-based engine enables a single user interface to work beautifully on both iOS 6 and iOS 7, and respond dynamically to changes in the size of controls, rotation, or localization. See how the improvements to Auto Layout in Xcode 5 make it even easier to quickly build flexible, modern interfaces.
Speakers: Kevin Cathey, Tony Ricciardi
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript has potential transcription errors. We are working on an improved version.
How you guys doing? Oh, come on. You guys aren't [noise] yeah, here we go. I'm about to say like this is a 10:15 session, right? You guys are way more awake than the 9 o'clock. All right! My name is Kevin Cathey, I'm one of the Interface Builder Engineers. And, later my co-worker Tony is going to be joining up on stage taking the reins.
And, what we're going to be talking about today is, hence the title, Auto Layout in Xcode. But before I talk about Auto Layout in Xcode, I just want to take a brief kind of crash course into what Auto Layout is. In case you're new to the technology, new to the platform. So let's do that real quick.
If I were to define Auto Layout in a sentence, which I've done, is that it is a constraint-based descriptive layout system. That was helpful. So let's look at what that means. So I have an interface here and I want to describe it once. But I wanted to look good in both portrait and landscape.
So what are some ways that I can describe the interface like I have here? OK. One way I could do it would be with the Hard-Coded Layout. But, when I rotate my device, if I keep my frame origin fixed like that, you know, 139,270, then it's going to be in the wrong spot when I rotate my device. So clearly, that's not what we want.
So what's another way that we could describe this interface? Well, if I were to go like to the white board and like describe it to someone, I might use terms like, the control is centered vertically in my container or, to fix the distance from the right edge, and this is exactly what Auto Layout is. What Auto Layout is, is it's taking this kind of white board human readable descriptions and its codifying them into these objects that we call constraints.
Now, what the automatic part is of Auto Layout is that you provide the constraints for us and then we automatically determine those frames based upon the constraints. Now, this is really cool and really powerful for a couple of reasons. So, like I mentioned, first of all, it's relational. I'm just describing it how you would describe it to someone if you were just explaining it to them in the hallway or on a white board.
And this relationship-based layout is also going to benefit us in other ways too, especially when things around us start changing. This is the fun part of writing code, right? So, for example, let's talk about metrics for a second. I already talked about rotation where the size of container is changing based upon the orientation of our device or the think about screen sizes, the difference between a retina 3 and a half inch and a retina 4 inch.
Or as we've been talking about so far with this WWDC, the differences between iOS 6 and iOS 7 where not only do we have changes in the metrics of controls like UI switch and UI slider, but we also have a great new dynamic text feature where the user can actually change the size of the font on the fly.
So, using Auto Layout and using relationships to describe things like spacings, alignments, equal sizes, these are the things that are going to translate regardless of what the size of the container is, so the size of the control, the size of your contents. So, let's talk about content. So, Localization is a really common place that this comes up. Now you guys are all localizing applications, right? I can just assume you are.
I'll take it by the yes's in several languages that you are, great! If you're not, then this is a great time to start doing so, 'cause not only it will benefit you for Localization but also all of the things I've been talking about. So let's talk about expressiveness.
With Auto Layout, you can do things that just weren't possible before without writing a lot of code. And as we all know, writing code is writing bugs, less code equals more awesome most of the time. So with Auto Layout, you can express really powerful relationships, and if you're using Xcode in Interface Builder, you can express these really powerful relationships again, without writing a single line of code, and that is just a huge win.
So, as we've kind of been saying so far with WWDC 2012, this is a great time to start adopting Auto Layout. And so you might be wondering, well, how do I do that? I don't even know where to start. So, the first place to start is with Interface Builder.
If you guys are using Interface Builder, the first step that I like to recommend is that you go in Interface Builder and you upgrade your documents to start using Auto Layout and you add constraints. Now, let me pause here and mention something that I think it's really critical to talk about when it comes to some of these new technologies.
Auto Layout can be adopted incrementally. It's not an all or nothing thing. You don't have to turn it on for you whole app, make it work all at once, right? We all have deadlines. And, sometimes the task of adopting a new technology looks daunting given a deadline. But, with Auto Layout and many of our new technologies, with iOS 7 and OS X Mavericks, is that you can adopt them incrementally, bit by bit. So, with Auto Layout, the kind of granularity for this is per view controller or per Interface Builder document.
And you can add just that one piece in to use Auto Layout, get it to work and move on to the next. You might only get two or three view controllers working, the place is what makes the most sense then say, "You know, I have to ship," great. After the release, come back, and keep moving on. So I just want to make sure that's really clear as we go on.
Now, a lot of us do things outside of Interface Builder with code, we add extra subviews, make little adjustments here and there. And this is the last part of adopting Auto Layout is to go to those places where you're adding subviews dynamically at runtime and you'll need to update those call sites to be aware of Auto Layout. So previously, with the springs and struts system you would do things like setFrame, addSubview, things like that. You'll continue to call addSubview, but instead of calling setFrame, now what you want to do is either add constraints or modify those constraints.
Now, the risk of being overly complicated too quickly, I'm going to point out one thing that I want you to be aware of as you're adopting Auto Layout and this property called translatesAutoresizing MaskIntoConstraints. What this does is it just tells the system, "Hey, I want you to help me by generating constraints that exactly mimic the Autoresizing Mask. So go back to this idea of adopting incrementally. In code, you can actually get down to the level of adopting it per view.
Now if you want to add your own constraints, you're going to want to have translatesAutoresizing MaskIntoConstraints turned to "No," the default is "Yes." If you use Interface Builder, don't worry we'll handle all for you. But as you're adding subviews and code, you want to make sure you turn that off if you want to add your own constraints.
All right! That was like the 3-minute crash course into what Auto Layout is. If you want to know more, if you're still confused at this point, you can go check out these sessions from the previous WWDC, there's three great sessions here. So if you're watching the videos, hit the spacebar, go check this out. If you're in the audience, well buckle up.
All right! So let's talk a little about kind of how Auto Layout has come to be. So you may know in 2011, we first introduced Auto Layout, it was brand new for the Mac, brand new for Xcode, and it was all about helping you create Auto Layout interfaces quickly, with the Visual Format Language and with the Interface Builder's automatic constraint addition. Now last year, it was all about helping you build Auto Layout interfaces in more places, bringing Auto Layout to iOS.
Now, it's been really cool to get to work with you guys over the last two years. I've had a chance to meet many of you. And man, you guys are doing some cool stuff, like some really custom cool stuff. I just think it's awesome. And so, what we're going to do this year is we want to put you in the driver seat when it comes to Auto Layout.
And so, with Xcode 5 where we're introducing a completely new workflow for working with Auto Layout in Xcode, that will give you both kind of broad painting strokes for working with Auto Layout, but also that really fine-tune grained control that will help you accomplish and build those apps that are just fantastic.
Now, as we talk about phases of development, right, we're adding features that are going to help you in every phase of development. What are some of those different phases? Well, we all start here, right? Initial Layout, and this is just where you're dragging stuff out for the first time, you want to get stuff to show up.
At this point, I mean I'm not really thinking about rotation or localization, I'm just pretty much concerned with-- can I remember how to connect to a database and can I populate my UI label, that's pretty much what I'm concerned at this point, and getting things up and running as quick as possible. But then, eventually, I do want start thinking about how is my application going to adopt when I rotate, change devices, change localizations? And this is in an Auto Layout world where we start adding constraints.
And then we all go through the inevitable Debug cycle, well, except here at Apple 'cause we don't have any bugs. No, I'm just kidding. So we all go through that Debug cycle, we identified problems and fix them. And then we kind of push our interfaces often to this Maintenance Mode, right, I may make a few tweaks here and there, but generally we're not touching our interface for probably quite a while. And it's really important in this phase that when you're making those single edits to your document, that things aren't changing that you're not aware of.
And this is last arrow that kind of connects maintenance and Initial Layout. And you can think about this when you start your next version of your app, you shift from version 1, you shift to version-- and I'm going to start working on version 2. Your marketing guy comes in and says, "Great, let's change the whole thing." Awesome! So then, you need a chance and some tools to help you start over with some of your layout.
So what Tony and I are going to show you today is how with Xcode 5, we've added features to help you with each one of these phases. So what we're going to do is we're just going to walk through each one of these one by one. So let's start with, at the beginning, Initial Layout.
Now, again, this is just when you're first adding views, positioning, resizing, I mean the stuff-- you guys got the stuff, this stuff was easy. And again, when you're working in the space, you're not yet thinking about how it's going to react the changes around you. So, with Xcode 5, when you add a view, you get to add constraints when you're ready. Interface Builder is not going to add any constraints when you first add a view, you get to decide when that's best.
[ Applause ]
So then, you add a view, you don't add any constraints, and you build and run. Well, what do you expect to happen? With Xcode 5, if you haven't added any constraints to the view yet, we will at Build Time add fix position and size constraints, so that you can experiment very, very quickly without having to think about constraints again until you're ready.
Now, what this allows you to do is this allows you to separate your Layout and Interface Builder with your layout at runtime. What you are dragging around and resizing an Interface Builder, could be independent of how you're thinking about things at runtime and then you get to decide when you want to sync that up.
You might say, "OK, I want my constraints to reflect what I have in Interface Builder," or you might say, " You know what, I don't want Interface Builder to reflect what my constraints at." And we've added features that give you the precise control over when you want to do that and how you want to do that. Now again, at this point, I'm still thinking of my interface as a static entity.
But eventually, I want to start thinking about how does it react to changes, and this is when we start adding constraints. We've added a lot of new ways to add constraints with Xcode 5. And really, I think, the best way to show you is with a demo. So let's do that now.
So all the features I'm going to show you work with both iOS and OS X. But what we're going to do is we're going to look at just an iOS application here. And this is an app that you've seen in a couple of sessions, I believe, it's our adventure game. And what we're going to do is we're going add a Front End UI to this to kind of navigate around some of the things like a creating a new game, loading a game, things like that.
All right, so let's get started here. What we're going to do is we're going to build a splash screen by adding some buttons here. So what I can do is I can just-- here is my library, I'm just going to drag out a button and drop it, and again the first thing you're going to notice by zooming here with Interface Builder is waiting to add constraints until I'm ready.
All right, so, my artwork is going to send me a designer. My designer is going to send me some artwork so in the meantime I'm just going to fill in with a background color, just a placeholder background color here. I want to call this, if I double-click, I can edit the title. I'm going to call this "New Game." And I can just position this, resize this, and it just works just how I expect. Again, let's see, load game, and then the most important part for us as developers, the credits.
And then, whoops, I didn't mean to do that. And let's resize this, position them, all right, we're good. Now, I'm going to build and run this. Again, I haven't added a single constraint yet, but my document's using Auto Layout. And you'll see when I build and run my application and it shows up, it's going to show up exactly how it looks in interface builder.
And these are those constraints that we add at Build Time so that you can build run your application and quickly experiment with what you're doing. We'll even tag those constraints at runtime so that, if you start getting log messages and stuff, you can see exactly what object what Nib file those constraints came from right at runtime.
All right! So you can see the effect of our fixed position and size constraints when I rotate my device. Well, that's clearly not I want to happen. So let's go back to Xcode and let's add some constraints. I'm going to show you three ways in this demo to-- new ways to add constraints. You've already seen two of them, and I'm going to reiterate those first.
Let me stop this. All right! So the first way I'm going to show you is via Control-Drag. Just like you can control drag between views to add relationships like actions and outlets for views, now you can control drag between views to add relationships that are constraints. So hold Control, I can just could drag from this new button off to create a leading space to my superview. I'm going to pause again and point out a few things.
When you add your first constraint to a view, what you're telling Interface Builder is, "Hey, I want to be in charge of the layout of this view," and now what Interface Builder does is it starts trying to help you, by just pointing things out, and just making sure that you're getting the constraints that you want.
So there's two things I want to point out here: First, the constraint that I've added, I've only added one constraint, and the constraint that I've added is orange, which is indicating to me "Hey, I still have more work to do." The other that Interface Builder is doing is, it's showing me my Runtime Layout. Like I said, with Xcode 5, you can have your Design Time Layout and your Runtime Layout be different while you're building as you get to the point where you want to have the UI that you want.
And so, what Interface Builder is showing me is, "OK, this is-- this big rectangle here is where my Design Time Layout is, and this dotted rectangle is what the constraints would generate at runtime." And so what I can do is if I control and I got off the right edge, you can see that it jumps over that side.
So why is it-- it actually have a height, I haven't add any height constraint, why does it have a height? And this goes to one of the concepts in Auto Layout that is also really powerful, which is the idea of the intrinsic content size. Most views like or most controls rather like labels, buttons, other things like that have a size that is like they're sized to fit size, think about it like the size of the text of a label, that's a great example of something that-- the intrinsic content size is. So from my button, the intrinsic content size is the size of the text, New Game. So in this case, the height there is showing me, the height of the string game.
So, Control-Drag is context sensitive. So based upon the views I'm dragging between and the angle of the line that I'm drawing, it will give me suggestions. So if I'm drawing out a vertical line and some horizontal, you can see it gives me options for vertical or horizontal-- vertical and horizontal constraints.
We have a top space here and then our horizontal constraint is centering, so based upon that line that I've just drawn. So I can pick a top space and then I'm going to draw one more constraint here which is the height of my button. Now, generally, you do not want to add explicit width and height constraints.
If you add an explicit width or heights constraint, then as the intrinsic content size changes, say when the font size changes or the string inside of it changes. That control will not change size so you might get clipped text or really awkward spaces. Now I'm adding a height constraint here 'cause this is a custom button and there's artwork that my designer will provide for me later, but for now, I'm just going to add a height constraint. But when I got my artwork, I would probably want to delete this.
All right! So just like I can create constraints between my superview and across myself, I can also created them by siblings. So to do that, I can control drag from new game down the load game, and you can see I get a few more options here, I get a vertical space, I get some alignments on the left, center and right, and also some equal sizes. So I'm going to select vertical space.
That constraint is orange telling me, I still got to work to do so I'm going to add some more constraints. I can add them one at a time or I can add multiple at a time. Before I do that, I'm going point out something else. Well, just this little dot right here which is telling me that I've already added this vertical spacing constraint.
All right! So now I can hold command or shift to add multiple constraints at once. So I can do left and right, I can hit return or just click away, and it's added those two constraints really quickly. And now I can finish off my view by adding my height constraint. Great! I've go my two buttons done here.
Let's talk about the third button here. The third button you can see here doesn't have any constraints yet, and it still not kind of fixed position and size state. When you build and run your application and Interface Builder adds those fallback constraints. If you haven't added any constraints yet, it's per view. So you can as you get them up and running, you can work on like one part of UI, move on to the other part of UI, and work on it again incrementally.
Now, I can control drag between all my views to add constraint which is again a really precise and quick way to add constraints. But right now, I just want to kind of get more of a broader paint stroke. I want Interface Builder to give me a suggestion of constraints that I can work with.
So to do that, I'm going to use the new Auto Layout Issue Resolving Menu, and Tony's going to talk more about this later, but I'm just going to point out a few things, so let's zoom in down here and I can pop this guy open. It's got a bunch of different commands here for doing larger brush strokes with constraints.
One of these is reset the suggested constraints. That will clear any existing constraints I have on just this view, and then it will add some suggested constraints for me, that sounds great. So I select that, and you can see it's added the exact constraints that I would add with Control-Drag, left, right, spacing, and a height constraint, perfect.
That's exactly what I wanted. And now, we build and run our application, you will see that our layout comes up, looks great in portrait and in landscape, well, OK, horizontally it looks good. We still got to work on the vertical. Let's go back to IB and figure out what we need to do.
We rotate that back, we write Xcode. And if I select all my views, it will show me all the constraints for those views, and there is my obvious constraint that I don't want anymore which was this top space to my superview. I would really like all the buttons to stay centered. So, with Xcode 5, it's very easy to get rid of a constraint I no longer want. I just select it and hit the Delete.
[ Applause ]
Who knew that deleting would be so exciting? All right! So let's add the constraint that I actually want which is our center vertically in our container. OK. Now we should be good if I build and run. It looks great in portrait, great in landscape. All right! So those are the first two ways that we can add constraints. Control drag and the Auto Layout issue resolving menu.
OK. Now we're going to move on to a few more interesting example is we're going to combine some of the different techniques, and I'm going to show you the third way that we add constraints. So again, I can control drag between views to add the constraints. I can control drag between scenes to add actions and it just automatically detects the context and it gives me what I need. In this case, I want to add a push segue.
Now, in my new game view controller, we're going to add a few different controls here. We're going to add one for being able to select my character and I want to add one for adjusting the strategy that I want, and then I want a big old play button so I can start playing my game. Let's start with the play button that sounds exciting. So once again, I'm going to drag out a button and I'm going to give it my background color, my design-- just for right now until I get my artwork, which will someday be delivered by my designers.
I type in play here and then let's go ahead and position this, resize, snap, good. I'm going to show you the third way now to add constraints. Control drag offered you a precise way to add constraints, and you can add a few at once. And then the Auto Layout issue resolving menu allowed you to do broader strokes, and now I'm going to show you the constraint-addition popover where I can kind of do a combination of all of that.
So down here in the bottom right of my canvas, I have my little pin button, I can select that and a popover comes up. And let me kind of walk you through some of the pieces of this popover. At the top, we have something called "Spacing to Nearest Neighbor," OK, what's the nearest neighbor? The nearest neighbor is the nearest sibling in the direction indicated. So the nearest neighbor off the left edge, the nearest sibling off the right edge, bottom edge, top edge, and so on. If there's no sibling, then it picks the superview.
So in this case, it's showing me that it's going to pick the superview 20 points away 'cause I don't have any other siblings, and so I can just select that I want these constraints just by clicking these little iBeams[phonetic]. So I want 20 on the leading, trailing, and bottom edge. And I can also add a height constraint just by checking height. And then I can go ahead, add my constraints and viola, I have my constraints really, really quickly.
[ Applause ]
But it gets cooler. So like I said, Interface Builder, you can do your Design Time Layout and your Runtime Layout, they're kind of-- they're separate, but when I add constraints I cannot do both my Runtime and Design Time Layout at the same time and let Auto Layout do all the work for me. So I'm going to add some buttons to select between my archer or my warrior characters. Quick poll, warrior or archer?
- Warrior.
- Oh, that's why it's going first. All right! So we're going to add a button here and warrior will be our first choice here. And then I'm going to duplicate this by this option dragging. I'm going to call this my archer. All right! So, I want these buttons to be the same size, I want to have them to be space, all space apart, space the-- my container and at the top. Now I could position and size these all myself right now or, again, I can let Auto Layout do the work for me.
So I'm going to open up my constraint-addition popover again, and these text fields are editable. So what I can do is punch in 20, 20, 20 and what that will do is it will add a leading top and trailing constraint at 20 each. For both of these, it will just do it to my container on the top, and then for my warrior it will do it to my superview, and for my archer, it will do it to the warrior.
On the trailing edge, it will do archer to my superview and warrior to my archer. Kevin, you say, Kevin, you're just going to add two constraints still in the middle. When you add constraints using the constraint-addition popover, however, we will unique the type of constraints so you're only end up adding one of that type of constraint when we go to add it.
Now, I can also say that I want them to be the same width and I can also give them a height so my designer says, "A hundred," I say, "Sure." And now, I can quickly add the constraints button which will not touch my Design Time Layout, I'll just add the constraints. Or, I can click this nifty add and update frames button, it will add the constraints and then it will size in position to views in the canvas to match the constraints. So I click that, boom! Constraints and layout all in one action.
[ Applause ]
And you could see how this can help you get through what you're going for to show quickly. You can just drag out views. You don't really need to [inaudible] their position, you can add constraints and let Auto Layout do that work for you. It's actually pretty cool. All right! So, you might be able to tell what these pictures are, but I'm just going to add some labels just so that we make sure we know what we're looking at here. So I'm going to add warrior label and position that right here, and then I'm going to do my archer.
Let's make sure he's centered. OK. Now I'm going to combine techniques here and show you how you can-- again, you can think about layout in a way that you want to think about it. So I can Control-Drag between my warrior to my-- label to my warrior image 'cause I know I want a vertical space. So I know I want vertical spaces for both these labels through their respective buttons. Now, I'm having stage fright so I forget whatever constraints I need to add. Never fear, Interface Builder is here to help you.
So they go to Auto Layout resolving menu down here. I'm going to point out one other command which is Add Missing Constrains. What Add Missing Constrains do is it will only add the suggested constraints on top of what you already have so that my constraints are no longer orange so that-- the position and the size of my view is fully specified. So let's click that, and you can see that Interface Builder has suggested to me to center X constraints and that's-- that's exactly what I want. Now, remember.
Now what you notice again is that Interface Builder doesn't give us any width or height constraints, and this goes back again to what I was talking about earlier with this intrinsic content size. With things like labels that have text or other things that have text or content that you don't want to get clipped, you want to make sure that the size is being driven by the intrinsic content size, otherwise., when I localize this in another language and the strings get really long or really short, they might start occluding, overlapping, and I definitely don't want that. So that's why I don't have any width or height constraints 'cause that is coming from the system for me.
All right! So, that's an example of kind of mixing, mixing the different patterns of approaches here. And we're going to have one more piece to our UI, which is to allow me to adjust my strategy. So I'm going to add a slider that will allow me to either be weak or slow.
So I got a slider here. And so based upon, you know, how I'm feeling that day, maybe I'm really good at attacking my enemies, so I'm going to be a little stronger. Maybe I'm really good at running, I'm probably good at running away and so then I can choose to be faster.
So what I'm going to do is I'm just going to get an initial set of constraints here so we're going to go back to our menu here, and this is speed key for this, so you can learn that and quickly get the constraints suggested that you want. And now, I got a bunch of constraints so let's go take a look at what we got here. And the way I'm going to show you how to do that is, in the Size Inspector you can actually see a list of all of your constraints.
So if I select the weak label and open the Size Inspector and roll over this, you can see the constraints that have been added for this view. Now, I can see that this top space here, well, that's not really what I wanted. So again, it's as easy, I can select it in the canvas, or here I can just select it, hit delete, and now it's gone.
So what I really want is for my weak label to be centered vertically with my slider, I'm just going to hold control, I'm going to drag, and I'm going to get a center Y constraint and there now that looks great. Let's build it and run it, and see how it looks after we run it.
OK, wonderful splash screen, new game, oh it looks beautiful. Let's rotate it and, well, that's not exactly what I want. We don't want that stuff to overlap. So I go and tell my designer, "Hey, Mr. Designer, this step is overlapping, I need some more help here." Now, he gives me one suggestion which is to change the size of my images here so I say, "OK, let's do that." So I have this two height constraints, right, that I've created, and I can select both of those and in the Attributes Inspector I can change the value, he says, "OK, they have to be no smaller than 72." Now I want to make sure that my-- those two buttons for selecting my character never clip, never, never crash my slider or overlap with my slider so I'm going to create a constraint between my slider and my warrior label.
Now, when I drag that horizontal line, as I got farther and farther away, right, it's unclear whether or not you want horizontal constraints or vertical constraints. So again, based upon that line or actually in this case, we'll show you all the options so that you can quickly create the constraints that you want. A little pro tip, if you want to create both vertical and horizontal at the same time, just draw a diagonal line and then you can select the constraints that you need.
Now, I don't want it to be a fixed-- fixed position, right? I don't want it to be a fixed space. I want it to be able to be-- just make sure that they don't run into each other. So I'm going to change the relation of this constraint from a quality into an inequality.
So, I can do that by double-clicking the constraint. Now this a-- this will be available in a upcoming seed of Xcode 5 and I'm going to show it to you know. So, by just like double-clicking on the constraint I can change the relation from equal to greater than or equal, and then for the constant, I can open this up and I can picture different kinds of values here. I can punch in the value myself or I can say, use the standard value or the current candidate's value.
I'm going to select standard and what this is that will give me what the system thinks is the best spacing in between these two views. So I'm just going to use the standard space and there we go. Now that slider should never get a-- never get occluded by our warrior label. Now, I can build, run and preview this or I can preview this right inside of Xcode. To do that I'm going to use some-- a new feature of Xcode 5 which is our preview assistant.
And I love tips and tricks so I'm going to keep giving you guys tips and tricks. I can quickly get to the preview edit by opening assistant or I can select it here. But what I'm going to do is I'm going to hold Option and Shift when I select this.
And I'm going to get a little navigator and this allows me to target where I want to put the thing that I'm opening. So, this works with anything, any file that you ever open, any sort of link that jumps you and opens a file, you can hold Option and Shift and get this little picker.
I can pick a new window, I can pick a new tab, I can actually pick other splits and other tabs that are open. Now, in this case I'm just going to say opening the assistant. And I'm going to select that and you're going to see it's open the same view over here but now I can change attributes about this view to preview it.
So for example, I can say, what is it going to look like in landscape and you can see it's clipped. Now, I'd been thinking to myself, what does it look like landscape in iOS 6? I could change this or using our little navigation control, I'm going to open a second assistant.
So, again, I'm going to come up here, preview, hold Option and Shift and then I can target a new split and enter and now I'm seeing another view of the same view. I can rotate this, and set it to iOS 6. And now I can edit in portrait and landscape for two operating systems.
[ Applause ]
So, this makes it really easy to preview what you're doing. OK, so now I'm going to show it to you, I'm actually going to show you one more thing too. So, I'm actually going to close the assistant. We know that there's a problem here but I actually want to see this in my main editor and I actually with that problem right, right at my fingertips.
So, to do that, I'm going to show you what I called simulated metrics. And simulated metrics are just a way for you to kind of hint the Interface Builder, hey at runtime. The stuff around my ViewController is going to look like this and that will allow us to give you a design experience that matches that environment.
So I can select my ViewController by clicking down here. But I'm going to show you another tip and trick and I love tips and tricks and that's the ability to select views that might be occluded in your UI. So, if I hold Control and Shift or just Shift right click over my slider here and select I get a menu and this menu shows me everything under the mouse at this point in time. And so you can see I have my slider, my container view, and my ViewController and I can just quickly select my ViewController.
[ Applause ]
And now I'm going to change my orientation to landscape. Again, this is just previewing it right here and inside of Interface Builder and there sure enough, there's the problem with my warrior label. And what's happening is all the constraints that we've added so far have been required. And so, you've got to fulfill this.
So, Auto Layout has followed your beckoning and it's followed that but at the cost of clipping some of my content and I don't want this. So, I'm going to show you one of the powerful things about Auto Layout which is called priorities. Priorities are a way that you can indicate the preferability of something.
So, in this case, you know, I want my slider to be centered but if it's going to clip my content, well that's not exactly what I want. So, I can change the priority of my constraint to be basically like try to be satisfied but if you can't be satisfied then don't worry about it, just get as close as you can.
So, I can select my slider and select the horizontal, sorry, the vertical centering constraint, open that up. And again, I can punch in a value if I know what priority I'm going for but I can also get some suggestions now with Xcode 5 by opening the Menu. I can choose Required, High, Low, or what Interface Builder would do is actually analyzes your interface and it looks for that content which is clipped.
It will figure out which constraints are involved in clipping that label and it will figure out what priority needs to be changed on that constraint so that that label no longer gets clipped. And that's exactly what I want. I select that and it moves my slider out of the way.
[ Applause ]
[ Applause ]
All right, so what did we see in this demo? Again, with initial layout, this is when you're first adding your constraints and when you added view, you haven't added into constraints yet, it will add them for you at build time to fix that position and size. I showed you three ways to add constraints, using Control-Drag for that fine control, using the Auto Layout resolving menu for those kind of broader brush strokes and finally the kind of combination of all of it which is this constraint addition popover.
Now, one of the things that I did was I kind of waved my hands over a lot of kind of debugging and resolving some of the issues. So, how do you see what's going on? How do you identify those problems and to do that, I'm going to invite up my co-worker Tony and he's going to walk you through what that looks like in Xcode 5.
[ Applause ]
Thanks, Kevin. Good morning. My name is Tony Ricciardi and I'm also an engineer on the interface builder team. So, Kevin just gave you an overview of Auto Layout and showed you how you can get started adding constraints to your views and Interface Builder. Now, I'm going to over the next step which is debugging and resolving any issues you might encounter while designing your layout.
All right, so as you add and remove constraints to your views, your layout will transition through intermediate states. And you can think of this like you would think of writing code. If you were to build and run your app in the middle of writing a line of code, it probably wouldn't compile or even if it did, it probably wouldn't do what you want at runtime. So, in the same way, your layout and interface builder won't always be in a complete state and ready to run.
There are three different types of intermediate states you'll encounter. First you can have an ambiguous frame which means you haven't yet added enough information to one of your views to fully specify its layout. On the other hand, you can also add too much in which case you might end up with conflicting constraints.
And third, you can also have a misplaced view which means your view's frame in the Interface Builder canvas doesn't match the size and position. It's going to have at runtime based on its constraints. So, I'm going to into little more detail in each of these three intermediate states and show you few examples. And then after that I'm going to head over to Xcode and show you some new features we've added to help you quickly diagnose and resolve these issues.
All right, so first we have ambiguous frames. You can get an ambiguous frame simply by just not adding enough constraints to your view. So, if you we take my example here with my warrior imageView, I've added three constraints, one for the top space, one for the height and one for the width.
And together these three constraints specify its size and its vertical position but they live its horizontal position ambiguous. And you can imagine if I were to rotate the device, the system wouldn't know whether I want to keep it centered horizontally or keep at the same distance from the left.
Here's a slightly more interesting example of ambiguity. Let's say, now I have two labels with a horizontal spacing constraint between them and I have another constraint between each label at the edge of each container. When I rotate the device, the total horizontal space in the container grows and one of those labels need to be stretched to fill in that extra space. Without any more information the system doesn't know which label I want to stretch. So, my layout is once again ambiguous.
So you can get conflicting constraints by over constraining your view and it could be as simple as this example here. I've added two-- two height constraints to my warrior imageView saying it to be two different heights at the same time. You can also get them in slightly more subtle ways.
Let's say instead that I have three constraints, one for the top space, one for the bottom space and then one for the height. And together they add up to the-- the height of my screen in landscape mode but then when I rotate the device the-- the height of the screen grows and now those constraints create a conflict with the screen size.
The third type of issue is misplaced views and this happens when you resize or you reposition your view in Interface Builder without updating its constraints. So, let's say that now that I have four constraints that fully specify my imageViews layout and it's not ambiguous, it does not have any conflicts but then I decided, I really want to have it centered vertically in that container. So, I just drag it down to the center in Interface Builder and not it's misplaced because I still have that constraint at the top saying it should be 20 points from the top.
So, interface builder doesn't automatically update your constraints. And that's because it doesn't know what your intent is. It doesn't know whether you'd-- whether I want to update that height constraint and just stretch it down to the middle or that I want to get rid of it and replace it with a vertical centering constraint. So, rather than pick one of those options for you, it just makes it really easy to update your misplaced view.
All right, so-- so those were the three different types of intermediate states and we've added a ton of new features to Xcode to help you quickly debug and resolve these issues. And the best way to show you those features are with the demo, so I'm going to head over to Xcode now. OK, let's start with top one here. I'll select and drag up on its [inaudible]. OK, so when I did that, a couple things happened.
First I got that dashed rectangle and it tells me that my button is misplaced. And at runtime its frame is going to be where you see the dashes. Also, over here my height constraint turned orange and I got this little badge. So, that tells me that it's currently 32 point shorter than the height of the button in the canvas and that it explains why it's misplaced. I need to update that height constraint.
So, I could do that by selecting the height constraint and going over the inspector and adding 32 points to its value. But this is a very common type of operation. So, we've got a short cut for doing that. So instead, I'm going to head down here, and what I'm going to do is use this command here, Update Constraints.
So, this looks at your selected view, and it looks at all the constraints that are touching it, and it updates their values to reflect its current frame in the canvas. So when I click that, it's going to update my height constraint over there, and you can see now it's no longer misplaced.
All right, let's move on to the other buttons. I could follow the exact same, the back exacts in step, so I could just resize them and update their height constraints. But then I'd have to make sure I made them all exactly the same height. So instead, what I'm going to do is create an Equal Heights constraint.
I'm going to Control-Drag down here and choose Equal Heights. So, this constraint is going to make the system enforce the fact that they all have the same height. So, I choose that, I get a conflict. The reason why I got a conflict is I still have this old height constraint here, and it's telling me that it's 43 points tall.
So, now I have that constraint saying it should be 43 points, and I also went and added that Equal Heights constraint, saying it should be the same height as the Top button which is 75 points. So, I need to delete one of these constraints to resolve this conflict. I'm just going to delete that old height constraint because it's-- I don't need that anymore.
All right, so I did that. I got rid of the conflict, but now my button is still misplaced because its-- the frame in the canvas hasn't-- has-- is no longer reflecting that Equal Heights constraint. So, I could resolve this by going into the button's size inspector and adding 32 points to its height. But again, this is a very common type of operation, so we've added another shortcut for doing that.
And that's over here in the bottom of the canvas, back in our Auto Layout menu. So this time, I'm going to choose Update Frames. Update Frames resizes and repositions your views according to their constraints, so it makes their frame in the canvas match their frame at runtime. When I choose that, now my button is no longer misplaced and it's resized just like I wanted.
All right, let's do the same thing for the Middle button. I'm going to start by deleting its height constraints, so it doesn't-- so I don't run into that conflict. And I'm going to Control-Drag down and add that Equal Heights constraint. OK, so now my Middle button is misplaced because I have an updated site and by virtue of growing taller, it's going to push apart those other two buttons. So now actually if I select these buttons, you can see they're all misplaced. They're all either in the wrong position or have the wrong set. So, let's go back to the menu and update their frames.
This time, I want to point out the fact that this menu is divided into two halves, so we're zooming down here. It's divided into two halves. On the top half, we have command that apply to the currently selected view, and on the bottom half, we have commands that apply to all views in the current scene in your story board.
So in this case, I want to choose update all the frames in my splash screen view controller. So that's going to apply that update frames command to all three buttons at once. When I do that, it resizes or repositions all three buttons, and now they're not misplaced anymore.
[ Applause ]
OK, so you just saw a couple different ways to resolve misplaced views. Now, I'm going to move on to ambiguous frames. And to that, I'm going to head over here to my load game view controller. OK, so this is a table view controller, and it has a prototype cell. That prototype cell is going to get reused at runtime for every saved game that the player can load.
And the cell has a couple of labels here, and those represent the name, the name of my character and the date that I last played with that character. And when I select these labels, you can see they currently don't have any constraints on them, so at runtime, they're going to have fixed sizes, fixed frames, fixed positions and sizes.
So, I want to hit Build and Run now, and so you can take a look at this table view without, before I start adding constraints. All right, so here's our splash screen, I'm just going to tap on Load Game, and here's our table view. And so you can see all the labels are getting clipped, and that's because those static sizes that we gave them are just too short to fit their content at runtime. So, let's go back to IB and add some constraints to let them grow dynamically.
[pause] Let's start with our date label here. I'm just going to Control-Drag over and add a leading space constraint, that's just going to pin it to the left side of the cell. And when I did that, it gave me an orange constraint. It's orange because my date label is ambiguous, and I can also see this at the top of the canvas up here in the-- in our mini navigator. So, this button here is a mini navigator and it gives you a quick summary of all the unresolved issues in your document. So when I click that, it tells me the vertical position is ambiguous for my date label.
So, that makes sense because we've only added a single horizontal constraint. So, we need to add more constraints to fully specify its position. I could keep adding constraints to each of my labels until they're unambiguous, but instead I'm going to use another shortcut. So, when I head back to this menu, and this time I'm going to choose Add Missing constraints and Load Game Table at the cell.
So, it's going to apply that same Add Missing constraints command that Kevin showed you, and it's going to apply it to all-- both my labels at once. So when I choose that, my constraints turn blue and you can see now I have four constraints. And these are enough to fully specify the layout of my two labels.
So, I got a leading space constraint. I got a top space constraint. I got a baseline alignment constraint that's going to align the two labels vertically. And I got a little horizontal spacing constraint between them. So, you might be wondering why I didn't get any with or height constraints, and that gets back to the idea of this intrinsic content size that we get from UILabel. So at runtime, it's going to infer its size based on its content and that's going to let it grow and resize and our labels won't be clipped anymore. So, let's see what that looks like.
[Pause] All right, so now our labels are no longer getting clipped. The first two cells look great and the third cell, I have a character with a really long name, and that's just running right off the edge of the cell, and it's actually occluding my disclosure indicator here. So, what I want to do is add a little padding on the right side, so that that name label gets clipped before it runs over in the disclosure indicator, so let's do that.
All right, so I'll just control-drag over and choose trailing space. And that gave me a bit more padding that I wanted, so I'm just going to double click it and choose 40 points. So I did that, I got a new issue. This is a new type of ambiguity.
And it's ambiguous because if you add up the 3 horizontal constraints we have and the widths of the two labels, it doesn't quite add up to the full width of the cell. And so one of those labels needs to be stretched to fill in the extra space, and I haven't told Interface Builder which one I want to resize yet.
For situations like this when you encounter a new issue, and maybe you're not familiar with it, you're not sure how to resolve it. You want to get some suggestions on how to fix it. You can always head over to the Interface Builder outline view, and get some information. So, let's do that.
If you look here by my load game view controller, you can see I have this button here. And that's-- that indicates that I have unresolved Auto Layout issues in that scene. When I click on that, the AL view slides over and I get a list of the unresolved issues. Here's telling tell me I have content priority ambiguity.
All right, and I can find out what content priority ambiguity is by-- there we go, clicking on this button here. It gives me a detailed explanation of content priority ambiguity. Oh, OK. And here in the second paragraph, it says to fix, I need to increase or decrease the content priority of my labels.
So, you could think of content priority as how strongly a view wants to remain at its intrinsic content size? And in this case, I want my Name label to get stretched or clipped more easily than my Date label. So, I wanted the content priority to be lower than my Date label's content priority.
If I click on this button here, it gives me a suggestion for how I might want to fix this issue. So, it's offering to decrease the content priority of my Name label. And wants it to make-- wants to make it lower than my Date label's priority, and that's exactly what I want. So, I'm just going to choose Change Priority. And when I did that, oh, you can see my labels are no longer marked as ambiguous. They have blue constraints. So, let's hit Build and Run and take a look at that.
[ Pause ]
OK, there we go. So now, it's getting clipped with a little bit of padding, and it's no longer occluding that disclosure indicator. All right, so just saw a couple different types of ambiguity, and I showed you a couple of different ways to resolve that ambiguity. There's just one more feature I'd like to show you which is useful when you defined your own custom controlling code.
And so for this example, let's imagine that instead of this Date label here. I want to use my own custom data control that I've implemented in code. Actually, I already have a scene and the story board set up that way, so I'm going to scroll over down here.
OK, so this is the exact same table view only we have replaced that Date label with UIView, and that UIView has its custom class set to my date control class. You can see when I select it, I already have a bunch of constraints, and I can get more details on those constraints in the size inspector over here.
And in particular, I want to point out that it has a width and a height constraint. So, earlier I mentioned you don't want to add-- you don't want to add explicit width or height constraints to views that define intrinsic content sizes because then you risk clipping or getting somewhere in padding.
And my date control does define an intrinsic content size. However, Interface Builder only knows about the built-in system controls. It doesn't know about this intrinsic content size that I have implemented in code. And when I delete these height constraints, my view is ambiguous because Interface Builder doesn't have enough information to know what it size should be.
So for situations like this where you know you want to use information at runtime to get your intrinsic content size, you can tell Interface Builder, it's OK, you don't need to warn me about an ambiguous size, and you can do that by giving in a placeholder intrinsic content size. So, I'm going to click on this button and choose Placeholder. And now, I've just told Interface Builder to use this size as my intrinsic content size, and it's OK if I don't have width or height constraints. And when I did that, it's no longer ambiguous.
[ Applause ]
All right, so you just saw a bunch of different ways, a bunch of different tools we've added to help you resolve Auto Layout issues. First, you can use the canvas decorations to see how your view is misplaced or ambiguous or you can get a quick look at all the unresolved issues in your document using the mini navigator, issue navigator.
If you want to quickly update the constraints on your misplaced view or add constraints to an ambiguous view, you can use the Canvas Resolving menu at the bottom of the canvas or if you want some more information about your issue, you can always head over to the Interface Builder outline view to get more detailed help.
So, that wraps up the new workflows for Auto Layout in Xcode 5. Before we finish, I just want to add one quick note on compatibility. So all the features we discussed today are fully compatible with any previous OS version that supports Auto Layout, or we use these great features, and you'd be using Xcode 5, and your Interface Builder document won't be compatible with previous versions of Xcode.
If you really need your, [inaudible] story board to be backwards compatibility, you can always downgrade it in the File Inspector, but then you won't have access to these features. And of course and along with the new Auto Layout workflows and of course support for iOS 7, Xcode 5 brings along a new readable and diff-able XML format for this.
[ Applause ]
If you'd like more information, you can contact the Dev Tools Evangelist, Dave DeLong or you can post it on developer forums. We'll be having auto or-- we also have-- we also recommend you checkout the Auto Layout related sessions from last year's conference, or the Interface Builder session for this year's conference. And with that, thank you.