Developer Tools • iOS, OS X • 53:43
Xcode 4 seamlessly integrates Interface Builder within the IDE. Learn how you can use this integration to work more efficiently than ever before. Discover how Interface Builder in Xcode 4 makes it easy to visually design your user interface and create connections to your code.
Speakers: Kevin Cathey, Joey Hagedorn
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Good afternoon and welcome to Using Interface Builder in Xcode 4. My name is Joey Hagedorn and I'm an engineer on the Interface Builder team. Before we get started today, I want to answer the question, what is Interface Builder? And simply, it's the part of Xcode that we use to lay out the interface in our Mac OS or iOS application and then connect that interface to the rest of your application.
One of the first things that we learn about when we're learning to develop on Mac OS or iOS is the model view controller design pattern. And Interface Builder works really well with this, and it helps you sort of, See where the different layers break down between the view layer and the controller layer underneath.
So today, there are three big things we're going to talk about. First, I'm going to give you a tour of Interface Builder, just so you're familiar with the different parts of the application and how it works. Then we're going to go on to build a basic application. It's a Mac OS application.
And then finally, integrate a bunch of cool new line features to really jazz up the application. So if you're an iOS developer, this will be applicable too, because many of the concepts are really the same between Mac OS and iOS with the stuff we're going over today. So yeah, this is what it looks like.
Right in the middle we have the design canvas and you do pretty much exactly what you'd expect here. Drag controls around, views, position them on the canvas, change the way they look, select them. Pretty clear. The next part of the interface that I'd like to draw your attention to is the objects library. And the objects library comes with a bunch of preconfigured controls that you can use in your interface. You just drag them from the objects library into the design canvas to start working.
Once you drag them out there, you need to configure them. So we do that in the inspector area above. And there's three inspectors I want to show you today. First, there's the identity inspector. And we use that to change attributes about or change the identity of the object that's selected.
So the controls you'll be dragging out of the library are ones provided by AppKit or UIKit. And you might want to change it to be a custom subclass that you implemented yourself. So you can do that here. and the identity inspector. The next one is the Attributes Inspector. And the Attributes Inspector we use to change the way that controller view appears and behaves.
And the last inspector I want to show you is the size inspector. We use that to adjust the frame of the object that's in the design canvas and also its size and how it behaves when its containing view or window is resized. On iOS, we run into this when we try to handle rotation.
On the other side of the interface, we have the structure area. And in the structure area, you get a hierarchical layout of the different objects in your Interface Builder file. So if you build a really complex interface, this can be helpful for finding and selecting objects that are a little bit more-- you don't immediately see in the file you've created.
Now, no less important but maybe a little less visible at first is the making connections part. Once we design this interface, it's really important to hook it up to the rest of the application that you've built. So, for example, if you have this image view that's selected, you'll want some way to control it to perhaps set the image on it or change the image response to some user interaction.
So, to do that, we drag from the interface builder side over to the source code when we're using Xcode's assistant editor and it inserts a property that's hooked up back to that view that we made the outlet to. So, now, any time we refer to that outlet, we're referring directly to that view that is on screen. Another type of connection we make is an action connection. So, we're going to make a connection to the view that we made the action connection.
So, we're going to make a connection to the view that we made the action connection. So, we're going to make a connection to the view that we made the action connection. So, if you have a button or a slider, when the user interacts with it, we need to respond to that somehow. And by doing the same sort of action, making a connection from that control over to the source code, instead, we can insert an action method and implement that method to do something when the user touches it.
So, I mean, that's the basic rundown of the different parts of the Interface Builder interface within Xcode. The design canvas, library, inspectors, and then making connections. So I think the best way to really get a good grasp on this is to just start building an application so I can show you how it works.
Take a look at our app here. This is what we're going to start out with. And it's a simple utility that helps us identify different directories on our hard disk and see how much space they're taking so we can find out what's using up all our space on the disk. This is a little basic, but this is what we'll start with to see how the tool is used.
Here we are in Interface Builder, and to begin designing this, I want to grab a table view out of the objects library and put it onto the screen. So I'm going to go up and show the utilities area from the button in the toolbar and come down to the library at the bottom, type "filter down to table view." And simply drag one out.
As I do this, before I let go, I'm going to line up the blue layout guides that will help me make sure this view is laid out in accordance with the user interface guidelines. So I'll let go and resize it, fill the window also using layout guides. And now I want to fix up the table view so it looks sort of like how we want it to behave, how we want it to look. I'll click again to select it and one more time to go inside to get the table column and simply resize this.
I want those blue and white stripes for alternating row color. So I'll click outside to deselect and then select again to get the table view. Now we're looking at that over in the attributes inspector, fourth tab, and if I look down the different options, one of them is alternating rows.
and we've set it up. At this point, the interface pretty much looks like Just like that picture that I showed you, I mean, there's no content yet because our app's not running, but the visual layout is where we want it. But the thing I haven't done yet is hook it up to the code underneath.
There's a couple things to do. First, a little bit about table views. The way that they work, in this example, is a cell-based table view. It has a data source and delegate object that it refers to, and it asks those objects questions like, how many rows does it have, and what are the content of those rows, before it draws itself on screen. So we need to make those connections to, I've already implemented those methods in the application delegate. I could show you the source code for that. Pretty simple.
Right here at the bottom, we've got a couple of methods here that just answer those questions for the table view in our application delegate object. And also, we refer to the table view right in our application did finish launching method to tell it to reload data. So let's establish these connections.
Back in our Nib file, if I hold down Control and click on the table view, the connections panel comes up, and we see we have the delegate and data source outlets there, but they're not connected to anything. I'm going to go ahead and show the structure area here to make it a little easier, bring that panel back up. And then if I just drag from data source to the application delegate object, do the same thing with delegate, now the table view knows which objects to go check with to answer those questions.
I'm going to hide the project navigator here and bring up our assistant editor. Now, the assistant editor is in automatic mode right now, and that means Xcode is going to try and find the source file that it thinks is most relevant to the selected object right now. We could go into manual mode or there's a couple different split modes, but automatic is what we want right now. And I'm going to hold down Control and click on the table view here and establish, let go right in the source code under the other property there, and choose to insert an outlet connection called main table view.
When I do that, we now have a IBOutlet property that when we refer to it in source, we're talking about that table view. So if I switch back to basic mode here and run the application, we have a working basic application. So with that, we've laid out our interface.
Change some of the properties so it looked, change some of the attributes of the table view so it looked just like we wanted it to look. And then made connections so that it actually did something. That's fine, but it's kind of a bland little demo app. Let's add some new Lion features to make it work better.
So here's what our app looks like right now. The first thing that we can add really easily in Interface Builder is full screen mode. We'll do that. Then I think this really enhances the interface. Rather than using the traditional cell-based table views, we'll switch to a view-based table view. Rather than running a custom NSL subclass to do this, we can design our views in Interface Builder. This is similar to how table views work on iOS.
And then finally, we can add a table view will add this NSPopover with a custom view that displays a tree map of the contents of our directory and use Auto Layout to lay it out much more effectively. My colleague Kevin Cathey will come on stage later to demonstrate some of those things. I'll just get moving with adding those features.
Before we start on the line features, there's one more thing that I didn't do in the previous demo, and that was adjust the way-- I didn't go to the size inspector and adjust the way that the table view behaves behaves when the window is resized. So all I need to do is select the scroll view and then head over to the size inspector and We have a little example of what's going to happen when the window is resized.
You can see that the red dot is going to be our table view, and the window will just get larger and smaller around it with no effect. So to fix that, we can adjust the auto-resizing mask by indicating it should expand when its container expands and indicate a fixed border between it and its enclosing view. And now it'll behave properly.
This is important to do when trying to support rotation on iOS, but we've got a better solution for using Auto Layout on Mac OS X a little bit later in the talk. So back to those Lion features. First thing to do is support full screen mode. This is really easy in Xcode 4. So we'll just select the window.
Choose the attributes inspector, the fourth tab. And if we look down here, there's an option for full screen. If we just change it from unsupported to primary window, we've adopted full screen with this window. Pretty easy. But-- We should also probably add the default menu item so that users can easily get into full screen mode. I'll open the window menu by clicking on it, go down to the objects library, Type in "full" for full screen.
And just drop the menu item in there. Now we've really fully done it. Next, let's get started on the real enhancement here, which is adding the view-based table view. So for one, because we have the power to design each of the cells directly in Interface Builder, we don't need a couple columns anymore. We can just do it with one more interesting cell. So select the table view and change the number of columns from two down to one.
I'm going to do some more resizing. So I'll resize this column to fill the whole table view. And then I'll go down to the Objects Library and switch it into view-based mode. So all I need to do to do that is grab a
[Transcript missing]
The cell that I'm laying out is going to be the prototype that will be used in each of the rows. So I just fill out this one cell that's used as the prototype. Then in one of the table view delegate methods, we fill it in with all of the data.
So I'll do a little more layout here, make the image a little bigger. If I hold down Shift, I can resize proportionally. I can use the arrow keys to nudge the label. And I want another one pretty much just like it for the... This one will be for the path. I want one for the size. So I'll go to Edit and choose Duplicate.
Got a copy of it. Can drag it around. This one I want to be a little bit diminutive, so I can go back to the size inspector and change the size from regular down to small. And also back in the attributes inspector, I'm gonna change the text color from black to dark gray that I picked out earlier. I'm gonna give them a couple labels as well, just so we remember what they're for. Path. So path. And size.
To explain a little bit more about how the V-Base TableView works, I'd like to show you the source code changes that'll be necessary in our TableView delegate and data source. So I'll show the project navigator and look back at the application delegate. The number of rows is going to stay the same, but I'm going to have a different implementation of object value for table, column, and row. So I'm going to delete this and paste in my new one. And I'm also going to implement this method, view for table, column, row.
Every time the table view goes to display a cell, it's going to call this method. And inside this method, we're going to ask the table view to make a view with the identifier main cell. And then we'll refer to properties on that cell. So these are outlets to set the image, the string of the path, and the string for the file size.
The NS TableView cell class already has two of these outlets established. So when we dragged out the view with the gear on it and the label, the image was already tied to the image view outlet and the label was tied to the text field outlet. But we need to add one more outlet for the size text field. So to do that, I've got a custom subclass of NS Table Cell View. So I'm just going to drag that in that I prepared.
It's really simple. The only implementation is this one property. And I'm going to import that header here. And if I switch back to the nib file, we need to go adopt those changes. So one, when we ask the table view for the view with the given identifier, we want to make sure we get back an instance of our custom table cell view subclass.
So I'm going to select the table cell view. I'm going to use the structure area to do so by just disclosing down into the table view the first column and the table cell view there. And in the identity inspector, I'll type in the custom subclass. Additionally, we need to tell the table view this cell's identifier, which is main cell, which I wrote in the delegate method.
So now when we call that method on the table view in the delegate method, we'll get back a table cell view with this subclass, and we've identified it by this identifier. The other thing we need to do is hook up that outlet for the Subtitle label. So if I hold down Control and bring up the Connections panel when I click, I'm able to make a connection directly to the text field there and close this. And I can build and run my application And at this point, we have a much more interesting table view. We can take it full screen. That works fine.
So with that, we've adopted A couple of our new Lion features, including full screen and view-based table views. I'd like to introduce my colleague Kevin Cathey to show you a couple more of the interesting features we have here in Interface Builder in Xcode 4. Kevin? All right, good afternoon, everyone. How are you guys all doing? Excellent.
Good, good to hear. All right, I'd like to talk about two more features that are new in line that we've integrated into Interface Builder, and I'm going to start with popovers. And this popover is just a class that allows you to take a view controller of content and pop it over your interface.
And the easiest way to show that to you is, of course, a demo. All right, so I'm just going to hide this. I don't need this anymore. And let's go ahead and hide the navigators, too, so we can focus on our interface. All right, so adding a popover to your Interface Builder document is as simple as just dragging it in. So I can go down to the library here and search for popover. All right.
There it is. And you can see when I drag it and drop it in, I'm actually getting two things. One, I'm getting the actual popover controller itself. And secondly, I'm getting a view controller. Again, a popover is driven by a view controller. That's what shows the content. So Interface Builder will add one for you automatically.
Now, as is common with iOS, also common with Mac OS X, when we have view controllers, we want subclasses of view controllers. And this particular case is no different. So I have a view controller class that I've already created for my popover. And it's really simple, and I'll show it to you in a second. Let me just start by dragging that in.
Drag that guy in, and we're going to copy him in, and there we go. If we look at the code for this, it's really, really simple. This method and this method are delegate methods that are from the popover that just indicate particular points of the lifecycle of the popover. In this case, we have some data that we want to pass over, as Joey showed you that screenshot earlier, that big, awesome tree map.
We want to make sure that we pass off the folder that we clicked the detail button for, and so when we show the popover, we want to sync that up to our tree map and, of course, tear it down when we close. This method, the detachable window for popover, means that when the user grabs the popover and drags it, they can actually drag it off into a floating window. So I've implemented that as well to take advantage of that functionality. So let's go back to our main nib file and hook this up.
So I'm going to close that guy. And we're going to select our Popover View Controller and set the custom class. to NSPopover View Controller. So just an aside of what this means. When I set the custom class of an object in Interface Builder, what I'm saying is, hey, at runtime, I want this object to be of this class.
When you're working with objects in Interface Builder, you're working with real live objects. That's a real view controller. But what I can say is at runtime, I want my own custom class of that class to be substituted in. If you'd like more information about that, check out our documentation to find more.
So I set the custom class of our popover, but I also want to set the nib file so it loads the right nib file, and I can just set that by typing it in there. As I mentioned and I showed you in the source code, there are a couple delegate methods of the popover that we're using to help customize our popover. Now, the delegate of the popover is not set automatically when you drag it out, so we're going to set the delegate of our popover, in this case, to our view controller, but you could set it to any controller that you want.
If I right click on the popover, you can see we have a delegate outlet here. I'm just going to drag that and connect it right to my popover view controller. and that's how easy it is to set it up. But we don't have anything yet to show it. So let's add a button and let's wire up some outlets so that we can reference it in our code and show it. So I'm going to add a button.
and I'm going to use this rounded rec button. I'm going to change the title to show details. And because I'm not yet using Auto Layout in my document, I'm going to set the springs and struts so that when the table view resizes, it goes in the correct position. And I can do that from the size inspector.
is going to be anchored in the middle on the right there. All right. So now we need to actually insert some code to show the popover. And showing the popover is actually just going to be one line of code. So I'm going to open the assistant so we can make some outlets and actions. So the first thing is I want to be able to reference my popover view controller and my popover. So I'm going to create outlets for those. So I can just control drag right into my source code. Popover view controller. Sweet. And let's also do popover.
And now I want to show you that by using connect to source with Interface Builder, when we actually insert the outlet, we're generating all the code that is necessary for, in this case, a property. So if I switch to the .m file, which I can do by doing the navigate menu, jump to next counterpart, or the key equivalent.
You can see that we've synthesized our popover and popover view controller. If you're working on iOS and you insert a property outlet, for example, we will not only insert the declaration and the IVAR declaration, the at synthesize, if you have a dialog method, we'll also add the release for the instance variable, and if your file is owner, it's a view controller, we'll even insert the kneeling out of the property and view to unload. So all the work that is necessary to make sure that's done safely.
So we've got our outlets in place, and I want to insert an action. Now, I could switch back to the header file and insert the declaration of my action, but then my action would be visible to everyone who is going to use my class. I don't really want that. I kind of want this to be private to just the implementation.
Using connect to source with Interface Builder, I can actually just control drag actions right into the .m file. So let me scroll down to the bottom of the file, select my button, control drag in. Show details. And now I have an action right here with no need to put the declaration in the header file.
All right, so I promised you that showing the popover is one line of code, and here it is. All you say is say, hey, popover, show relative to this rectangle of this view, and then you can pass a parameter that specifies which direction you want the arrow pointing. It's that easy.
Now, we do have a custom subclass of our view controller, so we want to make sure we propagate our data for the folder that we've clicked the details buttons for. And so that's just good old boilerplate code to just pass along the data. And then we have to insert our import for our custom subclass. And I really like my headers all organized, so I'm going to put it at the top.
Great. So now we've hooked up all the actions and outlets, dragged out our popover, and let's see it in action. I can launch this. Oh, and we get a build failure. Let's check out what that is. I can show this by jumping right to the fourth tab of, the fourth navigator rather.
and you can see that there is a file in here that has a missing import or has an import for a file that doesn't exist. So we can nil that out. You can see how easy it was to use the issues navigator to resolve the build issues in your project. You don't need this, so let's run this.
All right, and here's our application. I can click on the show details button, and we get a popover, but there's really no content yet. We'll talk about that in a second. I can drag it. It becomes a window, which is resizable and positionable for the user. It's that easy to add a popover. Now, thanks.
So there is no content in here, so let's lay out some views in our popover, and we're going to do this using a new technology in line called Auto Layout. So what is Auto Layout? We've talked about it a couple times so far in the conference. And I just want to reiterate some of the things that we've been talking about and add a little bit more detail.
So in classic layout, when you're dragging a view in Interface Builder or in code when you're setting set frame, for example, you'll get these guides. You can see on the screen these layout guides which help you position the views in accordance to the human interface guidelines that we've defined for both Mac OS and iOS. Now, we've taken these-- what's interesting about these guides is the relationships that they correspond. But they still are only one-time visual helpers. As soon as I let go of the button in Interface Builder, the guides disappear, and I'm left with only a frame.
Now, by using only a frame to determine the position and size of review, that means that it can't respond to changes in the content of your application. If, for example, the string of this button were to change to something longer, the content will be clipped because the button isn't large enough. With Auto Layout, what we're doing is we're taking these guides and other things, and we're freezing these relationships that those guides represent into objects called constraints.
Then at runtime, instead of the frame being both the input and output for the position and location of your view in your window or in your view, it's rather just the output. The constraints or these relationships are what govern the final positions of your frames. And we think this is a much better way to lay out your interfaces.
So let's review this real quick. So we persist the Aqua guides or the layout guides as objects called constraints. They're relationships between one or two views, the most common case being between two views. For example, a super view in a button or another view in its peer. And these are real objects in Interface Builder, just like every other view or controller in your document. So you can interact with them, make connections to them, select them, inspect them, just like everything else.
So why do we think this is better? First of all, dynamism. As your application is changing, for example, maybe you have data that is updating the views or controls in your application, instead of having to write code that was to automatically relay out your interface, Auto Layout happens to do it for you automatically.
Secondly, simplicity. As you're using Interface Builder to lay out your views, we're taking those guides and we're translating those into constraints. So it's really what Max talked about in the developer's tools kickoff yesterday. It's a do what I mean. I drag it in the upper left. Stay there.
Third of all, expressiveness. With a whole new layout technology, we've also added some additional things to help create powerful interfaces which were never possible before without writing a lot of code. And we've made it easy without having to write any code. And all three of those are really, really evident if you localize your application. Localization can be a very fragile task if you're working only with views.
But if you're working with relationships to lay out your views, now localization is as easy as drag and drop. And to show this again, I'd like to launch and do a demo. All right, so I'm going to switch to the back first back to focus on our interface. And I'm going to switch to that nib file that we dragged in.
So this is our popover view controller, and the first thing I want to do is enable Auto Layout for the document. Auto Layout is enabled per document, so you can upgrade your nib files one at a time. You can even use the project navigator to filter for zip file and select them all and upgrade it if you prefer to do that route as well. To do that, I'm going to open the file inspector, which is the first inspector here. And I'm going to open the file inspector.
And then I can just check the use Auto Layout checkbox, and now my document is using Auto Layout. So let me show you how it works. So I can take a button, drag it out. You can see I get the guides. And when I let go, the guides are persisted as these objects called constraints.
And here the relationships are evident. I have a spacing between my button and its super view and another spacing between the top of my button and its super view. And it does what I mean if I grab the button and put it in the upper right. Then I get constraints that pin it there as well. It's that easy to create interfaces.
[Transcript missing]
All right.
So that's just really basic of how easy it is to drag things out and to use Auto Layout. Now, what exactly is Xcode doing? I mean, I didn't really do anything to specify these constraints, but they seem to be exactly what I mean. What Xcode is doing is it's picking the minimum best set of constraints for my views and my interface. Well, what is the minimum? We're avoiding two things.
First, we're avoiding ambiguity. We want to have enough constraints to fully specify the position and the size of my view. I can't just say, oh, put this button 12 points away from the edge of my super view. What about the size? What about the Y origin? Secondly, we're avoiding redundancy.
There are many different possibilities for constraints, but we want to pick ones that are the most preferable so we don't over-constraint. For example, if you look at this button here, there's lots of different guides that are active. When I let go, we only pick a couple constraints. What Xcode is doing is not magic. We simply assign different scores to each possible constraint, and we pick the ones that are most preferable or most interesting given your current layout.
If you'd like to learn more about kind of how AutoLayout works under the hood and more specifics of why some of these constraints are more interesting than others, I encourage you guys to check out the AutoLayout session that was earlier today. So you can't go back in time, but you can watch the videos. So I encourage you guys to check that out. That was this morning at 11.30.
All right, so let's actually build the interface for our popover. So I'm going to want these two buttons to maybe show more or less detail for my tree map view. And then I want a button maybe to open in the finder. So I can grab these buttons. All right.
Drag them down here. And I'm going to add one more button for open in Finder. And of course, we'll need a custom view for our actual tree map. Custom view. And again, you can see as I'm dragging this out, I'm not setting any - Auto-resizing masks are anything, yet the constraints are falling in exactly how I'd expect them.
All right. So I want to change the title of these buttons. And what I want to highlight here is one of the bullets on the slide of why Auto Layout. And that's dynamism. I said that as the content of your controls is changing, the interface will automatically flow around it. And that doesn't just help you at design time, at run time rather, but also helps you at design time. So look at the relationships that are on this button. I have a spacing here, here, here. But there's also that spacing between these two buttons.
With constraints, they're relationships that must hold. So even as the contents of the button change, that constraint will always be true. Let's see it in action. If I change the title of the button to more detail, you can see the button grows to fill its contents and it pushes that other button along with it so that it maintains that relationship.
For those of you that missed it, I can undo and redo just to show you that it's moving. Similarly, I can select this button and say less detail. You can see it grew in the direction that I expected. And finally, I can change this to open in Finder.
and you can see that grew exactly how I expected as well. As Joey pointed out, there's a new property for views in Mac OS X Lion called the User Interface Identifier. I'm gonna set that on my buttons. This helps with accessibility and a number of other things. So I'm gonna call this the Open in Finder button. And similarly, we're gonna change our identifier for Less Detail button. And one more.
[Transcript missing]
Now, I can preview my sizing of how I've laid out some of my constraints right here in Interface Builder. I don't have to run my app. And to do that, I just grab the edge of the view and drag it, and you can see those constraints are doing exactly what I would expect in terms of the resizing behavior that I want.
As I'm resizing views inside of a container, so I resized a container before, but as I'm resizing inside of a container, we won't apply the constraints automatically because you might want to resize things outside of the AquaSpace guidelines. However, you can, holding the command key, override this, and now as I resize, you can see it's applying those constraints and pushing that button out of the way. So I can very, very easily resize things and maintain all the relationships, have the window grow and everything, so that if I want to make one small edit deep in my interface, I don't have to make a bunch of other edits farther out.
Now, something interesting happened here. This I-beam showed up underneath this more detail button. If you look at the less detail button, it doesn't have this I-beam underneath it, but the more detail button does have the I-beam. What's going on here? This gets into something called the intrinsic content size of a view, or simply the size to fit size.
With Auto Layout, if you don't specify a specific width for a view, what it's going to do is it's going to assume the size that it needs in order to fit its contents. In the case of a button and a label, of course, that's its string. For like a combo box, it might be for the string of the text field plus the disclosure button. Not all views have intrinsic content sizes, and it's usually limited to controls.
Now, what I want to do is I want to keep my controls and views at their size to fit size. Well, why? If I specify an explicit width, as I've done here, if the string grows too big, it's not going to resize the button because I've said I want this button to be, say, 130-something points wide.
So you want to make sure that your controls that have content that's going to be changing, that they are their size to fit size. If you've resized a control and you get this explicit width or height and you want to set it back, you can do that by going under the Editor menu and going to Size to Fit, and you can see that goes back to its size to fit size, and that explicit width goes away, and now when the content of that button changes, it's going to grow or shrink as necessary to hold all that stuff.
All right, so we're just about done setting up our interface. I want to add in that tree map that Joey had showed the screenshot of. So I'm going to drag in the code for that. We're going to set up a custom class and an outlet, and we'll be good to go. So let me open the navigators here. I'm going to close the utilities. And let's go back to the finder. Here's our tree map view. You can drag that right in. We're gonna copy that in.
We're going to import our header file, make sure that's all in. And now we want to go back to our pop-up review controller. I'm going to hide these again so we can focus on our interface. And we're going to set that custom class. Again, this is saying that at runtime, I don't want this to be a generic NSV. I want this to be an FSTreeMap view. And finally, I'm going to hook up a outlet. And so right now we're in manual mode because we were looking at that .env file before.
So I can either reset this to automatic. And there's even a really good speed key for this. that will reset it for you automatically. Looks like it's not selecting this. That's all right. We're just going to restart Xcode real quick. There are no bugs in Xcode, so I hope you guys can find some.
All right, so here we go. Here's our pop-up review controller, and you can see I have an outlet for my tree map view. And I can just control drag right from that and hook it on up. And now, when I run my application... Open my popover. Oh, fantastic. I got that awesome tree map view.
Drag it off. It's its own window. And I can resize. And it's resizing exactly how I would expect for the most part. Hmm. I really don't want this button to overlap that button. Well, how would you fix that? Well, one way would be to go write a lot of code. But we can use some of the power of Auto Layout to insert additional constraints so that those buttons don't overlap.
Let's see that in action. So I'm going to go back to focusing on the interface here. I'm going to position that so it's right in the center. So while Xcode is creating relationships for you automatically, in this case, I have two views selected, and we'll show those constraints for the selected view.
I can also add additional constraints and relationships based upon the particular interface that I'm building. In this case, I don't want those buttons to overlap, so I can add an additional relationship to ensure that doesn't happen. To do that, I can go under the Editor menu and go to Add Constraint, and you can see there's a couple different types of constraints we can add. We can add ones that affect the width or the height of our view. We can put spacings between views. We can put spacings between a view and its super view, or we can even make things equal size and equal widths.
And these are just a few examples of different types of constraints you can create. You can also align views, and to do that, you actually just use the Align commands. So if I had two buttons that I always wanted to stay aligned, I could either drag them so they were aligned, or I could explicitly say, oh, align their left edges or their right edges, and that will insert a constraint for alignment. But in this case, I want to add a horizontal spacing constraint. So what I've done here is it's taken a relationship that's on the canvas. Currently, these two buttons are, oh, say, 300 points apart, and it's frozen that into a constraint.
But we really don't want these two buttons to be exactly 300 points apart all the time, right? We kind of want to just make sure they don't overlap. So I can actually inspect my constraint, just like every other object. So let me select that and open the attributes inspector. And you can see there are a couple different properties that I can set on my constraint.
In this particular constraint, a spacing constraint, I can change the relation from an equality, I want it to equal 300 points, to an inequality. So I can actually say, be greater than or equal to, don't always be equal or be less than or equal to. And this is a very, very powerful way to constrain the sizes of your views or spacings. In this case, we want a greater than or equal to.
And I really don't want 330, that seems like a pretty large number. I kind of want it to be whatever the minimum is that the system thinks is best. So I could either punch in a number here, or I could let the system decide for me, and there's a checkbox right here, I can click that. And so now my spacing constraint is be greater than or equal to the standard Aqua space between these two buttons.
I'm gonna, before I run this and show you it working, I wanna point out two things. First, that this constraint is bold and these other constraints that Xcode helped me create are a little thinner. You can always tell which constraints are yours and that you have created by looking for the ones that are bold. Secondly, for constraints that are not equalities, we add a little badge just to indicate you can see exactly which inequality you selected.
All right, so now when I run my application, bring up my popover, I really like that, and then resize. You can see the window stops resizing, so those buttons don't overlap. I didn't have to write any code to do so. But it's also an interesting thing that the window actually stopped resizing. How did it know to resize? I didn't ever set the minimum width anywhere. And this is a really powerful feature of Auto Layout in that it infers the minimum and maximum size of your window based upon the constraints of the views inside of it.
So if any of those relationships, those constraints, have to be broken, it'll just stop the window from resizing. This is really powerful, for example, if you are localizing or changing content. You don't have to be updating the minimum size of your window or picking one that works for all of them. Rather, Auto Layout just takes care of that for you.
So I want to show you one more type of user constraint. These two buttons, more detail and less detail, aren't quite the same size. So I kind of want to make them the same size. I can do that by selecting both. We're going to add a constraint. And we're going to insert an equal width constraint.
And so now these buttons will always be the same width. But I want to take it one step further. I actually want to make all three buttons in the bottom the same width. So I can select these two buttons and say equal widths. And now all three buttons are the same width. And you can even see that if I were to resize this guy. All three of those buttons are resizing along with me.
Now, you might be wondering, Kevin, you mentioned, though, that you want your views to always be their size to fit size. If all your controls are their size to fit size and you say make them equal widths, what it will do is automatically pick the larger width of all the different ones that are all equal widths. So that way, no matter what title is in any of those views, it will never get clipped.
[Transcript missing]
So I can select the constraint between the less detail and open and finder buttons. And you can see I have a priority field up here. And the priority 400 means as I resize the window, keep the window resizing, but make sure the contents of the buttons don't get clipped. Now, 400 is just a value in that range. If you want to learn more about those ranges, you can check out the great Auto Layout documentation to learn what those mean and what some of those different values are.
But I'm going to type in 400. And you can see that now the constraint in the canvas is drawing with a dotted line, which indicates that this constraint is optional. And AutoLite will try to make that true if it can, but will break it if it needs to.
So now, let's run this and show it to you in action. Let's run my application. Let's open this one. There's my great popover. I can drag it off. You can see all three buttons are the same size right now. But watch closely. As I resize, OK, I hit that minimum width. They're not going to overlap.
And the less and more detailed buttons are going to shrink to accommodate resizing the window up into the point that the contents of those buttons are not clipped. So you can just look at this interface and say, wow, we created something with really complex interactions that makes sure that our interface is always visible and nothing's ever clipped, and we didn't write a line of code.
So where is this really powerful? As we've talked about a little bit so far, localization is really where this shines a lot. So let me show you localizing this nib file to German, for example, or French. So my language experts have sent me over some strings files, and they are on my hard drive, so I'm going to go find those real quick. So I have three different strings files, one for German, one for French, and one for English. So I'm going to just drag in each one in turn. There's my German one, and let me drag in my French one.
And if you look at these strings files, they're pretty simple. They just have the translations. So now I can just take the strings file and just drag it right in Interface Builder. And you can see that it replaces all the strings, maintains all those relationships, and even grows the window to accommodate those. And similarly, if I localize it to French, It does the exact thing that I'm expecting with no code and no extra work.
So we've showed you a couple of different new features in Lion and how we've integrated those into Interface Builder to help you guys make applications that are even better than before. We showed you view-based table views, full screen, popovers, and of course the power of Auto Layout and using all of these different things.
To recap some of the things we talked about with Auto Layout, we want to think about constraints, not frames anymore. Constraints are the input that determine the output or the frame, position and size of your views. These are relationships that exist between one or two views and they're objects that you can interact with in your Interface Builder documents. You can make connections to them, you can inspect them, you can select them, and you can see all of them right in your document structure.
If you'd like more information about our developer tools or you have questions, you feel free to email our developer tools evangelist, Michael Jurwitz. Additionally, we encourage you to check out our documentation. We have a lot of great documentation on our human interface guidelines for iOS and Mac OS, for Auto Layout, and of course for Interface Builder, view-based table views, all that great stuff. And finally, if you guys have questions, you can voice them and ask them on the Apple Developer Forums.
You can hear questions from other people, answer other people's questions, and get answers to your questions. And with that, we'd like to point out three sessions that are related. Tomorrow, we encourage you guys to come see the storyboarding feature that is new in Interface Builder. Again, for those of you watching the videos, you can go back to earlier today at 11.30, the session on Cocoa Auto Layout. And on Thursday, there's a session on view-based and as table views to get even more power with those. And with that, thank you so much for coming and taking your time.