Essentials • 52:21
View controllers--including navigation and tab controllers--play a fundamental role in the architecture of most iPhone applications. Learn what view controllers are, how to use them, and why they are important to your application.
Speakers: Evan Doll, Alex Aybes
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Good afternoon. Yeah, yeah, whoo! Welcome to Understanding iPhone View Controllers. My name is Evan Doll, and I'm going to be joined shortly on stage for some demos by Alex Aybes. And we're both members of the iPhone software engineering team. Many of you in the audience have decided to take the plunge and start developing an application for the iPhone that you're eventually going to ship to end users. And even if you haven't, you're probably thinking about it. I mean, that's why you're here, right? So your first priority, I'm guessing, is to create a great iPhone application with a native look and feel and a fantastic user experience.
In addition, you've got a limited amount of time and resources. So you want to spend time writing the code that you care about that helps to differentiate your app from everyone else's. So if you can avoid reinventing the wheel, that's a big win. On top of that, it's never too early to start thinking about version 2.0 and adding features and extending your application in the future. So if you can set yourself up for that with work that you can do now, that's also a very big win.
So... What I'm going to cover today, first of all, is we're going to talk about designing an iPhone application. And we're going to talk about some ways that you can organize and present content on the iPhone, and specifically what the motivation is for using view controllers in your app. And from there, we're going to dive into building a real live iPhone application. And again, we're going to focus on using view controllers to your advantage. So let's get right into it and start talking about designing an iPhone application.
Many of you in the audience may have developed for other mobile platforms in the past, and you're familiar with how the constraints of a small screen can shape how you choose to design your application. And others of you may come from a desktop, perhaps a Mac OS X, Cocoa background, and you've got a pretty good handle on application development, and you want to know how your design skills translate for the iPhone.
So whichever perspective you're coming from, I think it's helpful to look at an application that exists on both the Mac platform and on the iPhone and sort of see what some similarities and differences are. So the application that we're going to look at is Mail, an application that we all know and love and use probably every day.
So Mail on Mac OS X presents a lot of information to the user all at once. We've got lists of mailboxes, lists of messages, maybe a message detail, and a message composition all on the screen at the same time. And these different types of content are divided by size. So we've got a lot of different types of content. We've got a lot of different types of content. We've got a lot of different types of content.
Meanwhile, in the iPhone version of Mail, it has the same responsibilities and goals as an application, and it shares a lot of DNA, but really it's a much simpler, more streamlined application. So let's look in a little bit more depth at what some of the design motivations have been for Mail on the iPhone.
One big point is that we try to focus our user on the data that they're viewing. If you think about applications like Safari and Maps, we try to fill the screen with the web page or the map that's being viewed. We avoid unnecessary adornments or controls. Even in Safari, we scroll the location bar, which is a pretty essential part of UI, out of the way when you're viewing a web page. In Mail, since we have so many different types of content, we accomplish this by showing one type of content at a time. So if you've got a hierarchy of data, it's really effective to just show one type of content on the screen.
And sort of tying these concepts together is a phrase that we like to use a lot internally when we're talking about the design of an iPhone app. And that's the idea of a screen full of content. And we're going to talk about that a little bit more later, but I wanted to get the phrase in your head so you start thinking about it.
So what are some different ways that you can connect screenfuls of content when you're designing an application? There are two very common patterns in iPhone applications for doing this. The first one is to use a navigation bar. The navigation bar appears always at the top of the screen. A second very common pattern is to use the tab bar, which appears at the bottom of the screen. So let's go into a little bit more depth on each of these topics and see how they're used in an iPhone application.
In an application with a navigation bar, you're generally presenting a hierarchy of content with parent-child or master-detail relationships. And as the user performs actions, we navigate into that hierarchy with the current context always reflected in the title of the navigation bar. And we also give the user some context about where they've been and what's going to happen when they press the back button by putting a title in the back button of the navigation bar.
In a TabBar app, there are several self-contained modes which live in parallel at the top level of the app. And the user is able to toggle between these modes by pressing on the TabBar buttons down at the bottom of the screen.
[Transcript missing]
So with this design concept in mind, let's jump in and start building an iPhone application. And the application that we're going to build is a very popular one here at Apple when we're trying to show off some new technologies. It's going to be a recipes application.
Apologies if you're already developing a recipes app for the iPhone. Maybe you can take some inspiration or not. Our recipes app is going to have three screenfuls of content. And the first one is going to be a recipe list. In this case, we're starting out with a single recipe in the list.
We're actually going to extend this app later in the sessions here at WWDC. But for right now, it just has chocolate cake, which is OK. We're then going to navigate into a recipe detail view that has a list of ingredients, some instructions, and a button which allows the user to go into a third screen which shows a photo of the finished product. So we've got three screenfuls of content here. And the way we're going to build this under the hood is to have three controllers in our application to manage those three screenfuls.
So we'll have a list controller, a detail controller, and a photo controller. And this might seem kind of innocuous or obvious, but it actually represents a lot of trial and error and experimentation in application development. On the iPhone application team, we tried writing apps in a lot of different ways. And we found that the most effective and extendable way to write an app is to think about the application.
And we found that the most effective and extendable way to write an app is to think about the application development. And we found that the most effective and extendable way to write an app is to think about the application development. And we found that the most effective and extendable way to write an app is to think about the application development.
is to think of it in terms of these self-contained controllers that you can extend and work on individually. It makes it a lot easier to find and fix bugs as well as add new features. So we wanted to make it really easy for you to use this type of pattern in your iPhone app. So we crystallized some of the aspects of this into a set of classes in the UIKit framework, and the first one that we're going to talk about is your starting point, and it's called the UIViewController.
UI View Controller is the basic building block for your application at the controller level. And it's responsible for managing a screenful of content and everything about that screenful. And generally, the way it'll work in your application is that you'll create a subclass of UI View Controller and fill in your application logic and behavior and anything specific to that screenful. And it'll wrap up the views, data, and the logic all in one self-contained piece.
So the first obvious responsibility of a view controller is that it needs to manage a view, right? So how do you hook up a view controller with a view? There are two ways to do this. And the first one that we're going to talk about is to use Interface Builder. Interface Builder is our visual, you know, view layout and design tool for Cocoa and iPhone applications.
And the way view controllers fit with Interface Builder is that you'll create a new Interface Builder document and you'll lay out your view. It may be a single view, it may be a really complex hierarchy of views, and you'll set up the properties and the connections between those views in IB.
And once you've done this, you'll then take your view controller subclass and set it as the file's owner. You can do this via the pop-up in the Interface Builder inspector. And this is basically saying that your view controller is responsible for managing your view. You're managing the entire contents of the nib, the Interface Builder document.
That's what the file's owner is. It's sort of a special object which is responsible for the whole nib. And once you've done this, you can hook up the view controller to its top-level view. And you do this by setting the view outlet from the view controller to the view.
And at this point, your view controller and the nib are ready to roll. You can instantiate a view controller by calling initWithNibName and bundle and passing the name of the nib. And at this point, you can use the view controller in your app. Somebody can ask it for its view. And that view will be loaded lazily. So the view and the nib don't get loaded when you call initWithNibName. It gets loaded on demand, which is a big advantage for your application's launch time and other aspects of the performance.
The second way to get a view for a view controller to manage is to do it in code. So to do this, in your subclass of UIViewController, you're going to override a special method called loadView. And this method gets called as needed, sort of on demand, whenever the view controller's view is requested and hasn't yet been created.
And within your implementation of loadView, you'll create your views in code. So you can set up--it might be a single view. It might be a whole bunch of views that are all related together. Whatever the case, you're then going to set the view property. In the same way that we set the view outlet in the interface builder case, we're going to set the view property on the view controller.
So the way this would actually look in code is that we would override loadView in our subclass. We would set up our views--in this case, some class called myView--and then we set the view property. And from here, the view controller is managing the view. So you can release it because the view controller is the one responsible for it. So we know how to give a view controller a view to manage. What other interesting things are there about UIViewController? There are a few--whoa, whoa--and we create it within it. In this case, we don't need to pass in a Nib name because we're not using a Nib.
There are some interesting hooks for application events that you can hook into with UI View Controller as well. And the biggest one is that when your view is about to appear on the screen, you'll get a callback in your UI View Controller subclass, where you can load your data from disk and prepare it for display. So this is another example of lazy loading. Rather than, say, loading your data from a database when your view controller is created, do it on demand when it's about to be displayed on the screen. And this will help your performance out a lot.
On the flip side, when your view is about to disappear from the screen, this is a great opportunity to save your data. So in most iPhone apps, there aren't explicit save/cancel buttons or pop-ups saying, "Are you sure you want to save?" A lot of the time, if your user has edited the data in some way, you'll just want to save it out automatically when the view disappears.
And this is also a good place to persist things like the user's scroll position or other aspects of the view which they might have customized. On top of all that, there are hooks in UI View Controller for supporting some more advanced features in iPhone applications, such as interface rotation and memory warnings, both of which are essential to iPhone app development.
And those are going to be discussed in greater detail in the Controls, Views, and Animation session, which is tomorrow morning, as well as the Mastering iPhone View Controllers session, which is on Thursday afternoon. So I encourage you to come and check those out. So we know how to use an individual view controller. But what we really want to do is link several view controllers together to make a full-featured application.
That's the most interesting application of view controllers. So how do we do that? If you remember, we talked about a couple of really common application flows in iPhone apps. And we wanted to make that really, really easy for you to adopt. So there are a couple of classes in UIKit that you can use. The first one is for creating navigation bar applications. is called UI Navigation Controller.
And the idea with UI Navigation Controller is that it manages a stack of view controllers, as well as a nav bar at the top of the screen. And the Navigation Controller takes care of transitioning, positioning, sizing the views to fit the content area, as well as updating the navigation bar to match. So the way this fits together is that the top view controller in the stack has its view displayed in the main content area between the navigation bar and the bottom of the screen.
Additionally, the top view controller's view--or title--is displayed in the nav bar at the top of the screen. So this gives the user some context about where they are. And you don't need to set this yourself. As long as the view controller has a title, it's displayed in the correct way automatically. And finally, the previous view controller's title is displayed as a back button on the left-hand side of the screen.
So how do you actually get view controllers into a navigation controller? There are two main operations for doing this. And if you're familiar with some computer science terminology, you'll know what they are. The first one is to push. So if you want to add a view controller to the stack, you'll call pushViewController with the view controller that you want to add. And you can tell it whether or not to animate. There are some cases where you want to animate and other cases where you don't.
To remove a view controller from the stack and do the corresponding animation to animate it off the screen, you'll call popViewController, and you can tell it whether or not to animate it. And you'll notice here, we don't pass a parameter to popViewController. It always operates on the top view controller on the stack. There are some other methods for manipulating the navigation controller's stack, but these are the two most important ones.
So when exactly do we call push and pop in our application flow? First of all, when you're setting up your initial navigation state, most often in your application didFinishLaunching method in your app delegate, you're going to create a navigation controller. You can do this in IB, or you can just call UINavigationControllerAlecInit.
Once you have your navigation controller created, you can then begin pushing view controllers onto its stack. So, for our first view controller, we're going to call pushViewController, pass it, and we're going to say no for animating, because when we first launch our app, we don't want the user to be seeing some side-to-side transitions. We just want it to launch to our first view. And you can actually push multiple view controllers here if you want your user to start several levels deep when you first bring up the navigation.
And finally, we need to display it on the screen. So, a navigation controller is actually a subclass of UIViewController, so you can use it anywhere that you would normally be able to use a view controller. So, most commonly, you'll call addSubView, passing the navigation controller's view as the parameter. And the navigation controller's view is a special container view, which includes both the navbar at the top of the screen and the content area for the top view controller's view.
So your app is up and running, and your user is interacting with it, pressing buttons and selecting table rows. How do you push and pop in response to those types of user actions? The most common place that you're going to push in your application is going to be from within one of your view controllers on the stack. So for example, within our recipe list controller, the user may press the button that says chocolate cake. And so we want to transition the chocolate cake detail onto the screen.
So what we're going to do from within the navigation controller is get a reference to our parent--from within the list controller, we're going to talk to our parent navigation controller and tell it to push. So what we'll do is call self.navigationController, which gets our parent, and then we're going to push some other view controller. In this case, we want to do it with animation because that gives the user a better feel for what's actually happening in their application.
Now, popping is a little bit different. You're actually rarely going to call pop directly. In fact, don't be surprised if you never actually call popViewController in your code. And the reason for that is that it's automatically invoked by the back button in a navigation bar. So this is such a common thing, we wanted it to behave consistently in navigation-based apps, so you don't have to write the code for this. It'll just work. So we're going to go ahead and do that. With all this in mind, let's start building the Recipes application. So I'm going to ask Alex to come on stage and we're going to start doing it.
Good afternoon. My name is Alex Aybes, and I work with Evan on the iPhone Software Engineering team. So let's actually go ahead and build this Recipes application. What I have here is an Xcode project. It is basically the Navigation Controller application template, with a couple of things I changed and actually removed for the purpose of the demo. So the first thing we're looking at here is the Recipes application delegate. As you can see, it has a couple of outlets to a window and a navigation controller. Again, this is pretty much the template.
As you can see on the side here, we have a few additional view controllers. And we're going to cover those in a few minutes. So I'm actually just going to go ahead and run this application to show you. There's nothing in my sleeves. So as you can see, just a blank window in there.
So let's go ahead and build this navigation controller, the first step of the application. So when the application did finish launching method of the delegate, we're going to create our navigation controller, the basic step in there. So we're going to go ahead, call allocate the navigation controller, and then add the navigation controller's view as a subview of the window.
So let's build and run this. And as you can see on screen now, we have a navigation bar at the top and, again, a blank window because we haven't added any view controllers. So let's go ahead and add the first view controller. If you remember, this is the list of recipes we're going to add there. Let's go back to Xcode.
I have already created the RecipeList View Controller. Let's take a look at that. It is a simple subclass of UI View Controller that has one action, the View Chocolate Cake action, which is going to be called when we press the Chocolate Cake button. So this view controller, we're actually going to create an interface builder. So I'm going to select the recipe symbol list.
Neb and Openit and edit it in Xcode. Let me hide the back. So, again, we have the files owner and the view. First thing we're going to do is actually set up the view. I cheated a little and actually set it up already. It's got a single button in there. Really complex for now.
So once you've laid out the view, you can close this. And the next thing we're going to do is set the class of the file zone. Again, from the slides earlier, we're going to set this to be the view controller. So we're going to go to the Tools menu, to the Identity Inspector. and said the class of the files owner to be the recipe list view controller. As you notice here, Interface Builder picks up on the fact that this particular view controller has one action.
Once we've done this, we're going to wire the view controller, which is the files owner in this case, to our view. For this, we're going to go to the connections inspector. and drag the view outlet to our view. All right, we've connected the view. The next step, we have an action in our view--a button, rather. So we need to wire that to the view controller's view chocolate cake method.
So in the chocolate cake method, I'm going to select the touch-up inside here and drag it to the files owner. Again, it knows that about the view chocolate cake method, so I'm going to wire it to that. All right, that's all we need to do in Interface Builder. So I'm going to close that Interface Builder document, go back to Xcode.
Now, this is the very first view controller we're going to push on the stack. So I'm going to do this in the recipes app delegate. Again, in the application definition launching method, we created the navigation controller. Next step is to actually create this first view controller. So we create the first view controller, the recipe list view controller, by calling alec, init with name name. This is the name we just edited in Interface Builder. And we're going to find that name in the main bundle.
Once we've instantiated this view controller, we need to push it onto the stack by just calling pushViewController on the navigation controller. Again, as Evan mentioned earlier, we do not want to animate this first one because this is before the application is actually shown to the user. This is the initial load of the application. Once we've pushed the view controller onto the navigation controller stack, we don't need to hold onto it. So we're actually going to release it. This is now owned by the navigation controller.
Once we've done this, let's build and run. And there we go. We have our view. The view we just set up in Interface Builder is now in our navigation stack. As you notice here, we don't actually have a title. Probably want to update that next. Let's go ahead and do that. Back to Xcode. This time we're going to modify the Recipe List View Controller. So, as I mentioned earlier, this is just a simple subclass of UIViewController. So, in the implementation file, in the initWithNameName method, nameName and bundle, we're going to actually set the title property.
Set it to recipes. Again, this is our recipe list. And build and run again. And there we go. We have recipes, the title. All we had to do, set the title property on that view controller. The next step is to actually hook up this chocolate cake button in there.
Right now it doesn't do anything because we have not done anything in the view chocolate cake method. So let's implement the view chocolate cake method. back in the recipe list view controller, the view chocolate cake method. We're going to create the next view controller. In this case, we have a view controller called the RecipeSimpleDetailViewController that I'm going to show you in a moment.
This view controller, again, uses a nib to define the interface. So all we need to do is call recipe simple detail view controller, and it will name. This is the nib it uses to define its interface, and find it in the main bundle. This name has already been set up, and I'm not going to cover that right now since it's essentially the same thing as the previous one.
The important thing here is how we push it onto the navigation controller stack. For this, remember, we're in the recipe list view controller. So we're going to get the recipe list view controller's navigation controller and push the detail view controller--the next one in the stack--onto this navigation controller. In this case, we do want to animate because this way the user is actually going to see what happens. Once we've done that, again, no need to hold onto it, so we're going to release it.
So with that, we're going to actually run the application again. And now, when I press the chocolate cake button, I see the recipe. This is the default nib. It's got a text view in it, and it has the default text right now. So let's go ahead and update the text in there.
Back in Xcode, now we're going to edit the next view controller, the Recipe Simple Detail View Controller, the one we just saw on screen. Here, again, as you can see, it says the title. There's a couple other things. Here we have this viewDidLoad method. This is a special method on UI View Controller that you can overwrite.
It is called once the nib has been loaded, once all the outlets have been connected. So at that point, you're good to go and you're good to set up. The recipe simple detail view controller is a simple subclass of UI view controller that has one outlet, the description view. And that's the UI text view we saw when running the application.
So back in the implementation, in the viewDidLoad method, we're going to actually set the text of that text view. So all we need to do, since the outlets have been connected at this point, is set the text to be the actual recipe. I don't necessarily recommend trying out that recipe.
So, view the chocolate cake, and there we go. We have the recipe actually displayed. Next step in here is to actually view the picture. Again, we haven't done anything there, so that button doesn't work. So let's actually go back to Xcode and implement this. As you can see, there's a show photo method. It's been wired in Interface Builder, same way the view chocolate cake method was wired earlier.
Just for a little change, we're actually going to build this third view controller and entire lane code, just to show you how that works. Before that, we're going to actually push it, create it. We have this recipe for the view controller that is, again, a very simple subclass of UIViewController, not even any instance variable. So back in the recipe simple detail view controller in the show photo method, we're actually going to, same way as before, instantiate the recipe for the view controller. This time, you notice we don't need to pass in a nib since we're creating this from code entirely.
And again, get our navigation controller and push the photo view controller onto the stack of the navigation controller. Again, we animate since the user needs to know what's going on. And we release the photo view controller once we don't need it, since we don't need it anymore, since it's on the stack.
Now, let's take a look at the actual recipe for the view controller. Again, I mentioned we're doing this all in code. So here, in the recipe for the view controller, we're going to implement the load view method. This is a method that will be called appropriately at the right time. You just need to create your view in there. So what we're going to do here is create a UI image with the chocolate cake resource that we have in our application, and then create a UI image view from that.
And here comes the important part. We're going to set the view property of our Recipe Photo View Controller to be that image view. Again, we release it since we don't need to hold onto it. The view controller is already holding onto it. All right, once we have that, we're actually going to run it. And there we go. We have the chocolate cake, the actual recipe, and voila, a beautiful photo of the final product. And that's it for our demo. Back to you, Evan.
[Transcript missing]
TabBar Controller manages an array of view controllers, as well as the tab bar down at the bottom of the screen. So the way this actually all fits together on the screen is that the selected view controller's view is displayed in the main content area between the tab bar at the bottom and the iPhone status bar at the top of the screen. It's automatically positioned and sized.
Some attributes of all of your view controllers which are being managed are displayed in the tab bar at the bottom of the screen. So as you can see here, the titles and some other properties of those view controllers are being shown. And this gets done for you automatically. You don't need to tweak the tab bar yourself. So UI Tab Bar Controller is actually a pretty simple class. And I think we're just going to jump in and show you how to build a tab bar-based app using it. So, Alex. Thank you.
All right, for this one, we're going to open a slightly different project. I'm going to hide this one, pick the next--the tab bar demo. This particular project is also a modified version of the template for the sake of the demo. We have our application delegate that has a UI tab bar controller in it, and all the application delegate really does is--let me-- Resize this. All it really does is set the tab bar controller's view as a subview of the window. Then we have a few subclasses of the UI View Controller--a chocolate View Controller, a cobbler View Controller, and a French macaron View Controller. The best one.
For a little change, we're actually going to do the rest of this entirely in IB. So let's open the main window interface builder document. I'm going to hide the Xcode in there. And there we go. This is pretty much the template main window. You've got a file owner, a files owner. That is actually in the identity class. It's just a UI application. You've got an application delegate, in this case, our TabBarDemoAppDelegate, and a window.
This tab bar demo app delegate, as you notice, has one outlet to the window and one outlet to the tab bar controller. So we want a tab bar application, so let's actually build it. We're going to go to the library in the objects, select the tab bar controller, and drag this into our main window, nib file. So as you can see, we get a little window here with a couple of items in the tab bar.
So we want three different tabs in there. So the first one we're going to set to the Chocolate View Controller. For this, we go to the Identity Inspector, again, in the Tools menu, and set the class. You can notice that Interface Builder actually auto-completes. It's quite nice and easy. The second item we're going to set is the second view controller. We're going to use the Cobbler view controller class.
And I mentioned we need three, so let's actually add a third one in there. For this, we go back to the library in Interface Builder and the objects, pick a view controller, and simply drag it into the tab bar. This will create a third item in the tab bar.
And again, I'm going to go back to the View Controller Identity Inspector and make this the Macaron View Controller. There we go. Next thing we need to do is customize those titles down here at the bottom. So for this, I'm just going to double-click in there and make this Macaron. And yes, this is the French spelling, if I can still remember it. The second one was Cobbler.
And the first one was Chocolate, of course. Excuse me. There we go. Last step in here, we need to customize those little icons there. Question marks aren't that great. So we're going to go to the Media tab, and this is our really artistic way of representing a chocolate cake. And then the cobbler.
And then we need the Mac run. Oh, we probably don't want that one. Let's actually use that one. All right. Last thing I need to do is wire the-- in the application delegate, remember we have a tab bar controller outlet. So I'm going to go to the connections inspector and actually wire this tab bar controller to our tab bar controller.
Yes, now you see we have a connection there. Let's close this. This is all we need to do in Interface Builder. So close, go back to Xcode, and build and run. And now we have a tab bar-based application. And if I select the different items, I see the different photos and the macaroons. All right. That's it for building a tab bar application in Interface Builder. Back to you, Evan.
So what did we just see? Again, we created several subclasses of UI View Controller and then plugged them into a plain, vanilla UI Tab Bar Controller to manage the transitions between each one's view. And then we customized the titles and the images to give our users a better idea of what was going on.
And again, we didn't have to manage any of this stuff ourselves. This is really common code in many iPhone applications, so we wanted to make it really easy to adopt. So you don't have to worry about sizing your view to fit in the space between the tab bar and the status bar or any of that sort of stuff. If you find yourself wanting to roll your own tab bar application flow, I really encourage you to take a step back and see if you can use the pieces that we've already created, because it'll save you a lot of time.
Next, so we've seen how to build a navigation and a tab bar-based app. But there is one more thing which I'd like to cover. Am I allowed to say that? Probably not. Think back to the first time you saw the iPhone demonstrated. And for me at least, the applications which really jumped out, which really amazed me, were the apps like Safari and Photos, which rotate their UI in response to user interaction.
You know, this is a really eye-catching feature that creates a lot of buzz. And wouldn't it be great if you could adopt rotation really easily in your application as well? One big advantage of this is that your users are going to want to show your app off to their friends. When it's time to whip out the iPhone and show it off at a party, they're going to say, "Check out this app. It rotates." And you're going to build a lot of word of mouth about your application.
Additionally, there are some more concrete reasons for supporting rotation in your iPhone app. Some types of content are not always the same. For example, if you're using a mobile phone, you're going to want to make sure that you're not using a mobile phone. You're going to want to make sure that you're not using a mobile phone.
You're going to want to make sure that you're not using a mobile phone. Some types of content just fit better in landscape. Photos, maybe some web pages. The keyboard, a lot of users prefer typing in landscape. So we wanted to make it easy for you to support this in your app.
So there are two steps to supporting this with view controllers. The first step is to decide whether or not to rotate. So in each of your view controller subclasses, if you want it to be rotatable, you're going to override a special method called shouldAutorotateToInterfaceOrientation. And the default implementation of this method just returns yes for the portrait right-side-up interface orientation. So if you'd like to support more orientations in your view controller, you're going to override this. And here, we're just going to return yes because we want to support any interface orientation out there.
And now, one thing worth noting here is that if you're writing a navigation or a tab-bar-based app, you need to make sure that all of your view controllers support the same set of orientations. This is currently a limitation of those container controllers. If you have some view controllers which support landscape and some that don't, the results currently are going to be kind of unexpected.
So if you have a view controller that supports landscape and some that don't, the results currently are going to be kind of unexpected. So if you have a view controller that supports landscape and some that don't, the results currently are going to be kind of unexpected. So you need to make sure that you're consistent in your support.
Once you've decided whether to rotate, there's a second step, and that's to make sure that your views resize to fit the available space on the screen. Because when you go from portrait to landscape, the available bounds of the content area will change. So there's a really easy way to do this, and it's by using auto-resizing masks on your UI views. So the way to do this in code--here, we want our view to grow and shrink both vertically and horizontally to fit the available space, as defined by its super view. So we're going to set the auto-resizing mask to flexible width and flexible height.
Now, if you're setting up your view in Interface Builder, you can do it there as well. And you use what we call springs and struts in the Interface Builder UI. And here, we're doing the exact same thing via those springs and struts. So our view has a flexible height and width and is pinned to all four edges of the screen.
Now, let's say we wanted to create a view that was flexible in terms of width, but was actually pinned to the bottom of the screen and didn't grow and shrink vertically. The way we would do that via the auto-resizing masks would be to use flexible width and a flexible top margin.
So the equivalent setup in Interface Builder would be this one right here. And sometimes this can take a little trial and error to get right. But the nice thing about doing it in IB is that, as you can see, on the right side, there's a square which grows and shrinks as the containing view grows and shrinks. So you can sort of simulate what's going to happen in terms of your view sizing.
This makes it easier to figure out what the right settings are. So once you've done both of these things, you're pretty much ready to go as far as rotation goes. There are some more advanced ways in which you can customize it, which are going to be covered in the talk I mentioned earlier, controls, views, and animation, tomorrow morning. So let's see this in action with the Recipes app. Let's make it rotate. So, Alex, one more time. One more time. All right, we have the recipes application. Let's actually go back to Xcode. I'm going to close the tab bar demo. Reopen our recipes application.
And I'm going to run it just to show you where we're at right now. Again, we have the chocolate cake, the actual recipe, and the photo. What happens when I rotate? I'm going to go to hardware in the simulator and rotate left. Well, nothing actually happens. If I rotate the other way, nope, nothing.
And none of our actual view controllers support rotation, so rotation is just not going to do anything at this point. Let's go to Xcode and Implement rotation. Let's make our view controllers rotate. As Evan mentioned, just one method to override in the view controller subclass. That's the "should auto-rotate to interface" orientation.
Another thing Evan mentioned, do it in every single one of your view controllers. So we're going to do that. In the detail view controller, You can do the same thing. Should it auto-rotate? And in the recipe list, again, should it auto-rotate? Yes, absolutely. It should auto-rotate. Let's run this. Now we're in the recipe list. We're going to rotate left, and there we go. We have rotation. If I rotate right, and again, it rotates. Fantastic. The next view, the detail view, let's try to see how this one rotates.
As you can see, not quite right. This doesn't look quite the way we want it to look. So this is because we haven't actually set up the springs and struts yet for this view. Let's go back to Xcode, or rather actually, let's go to Interface Builder. We're going to open the Nib file for this particular view controller. And here's the view.
The first thing we're going to do is make sure the background view is actually set up properly. So we're going to go to the Tools menu, the Size Inspector. And this is the background view. As we can see, it's pinned to all four corners-- to all four sides, rather-- and flexible height, flexible width, so we're good. Next on the list is the actual text view.
So this one is not actually set to size in any kind of way. So we're going to pin it to the top, the left, the bottom, and the right, and again, make it grow in both directions. As you can see in the little preview, great. This is actually going to expand as the view changes size. Perfect. The button, it is pinned to the right for some reason. We don't really want that.
All we want to do is to pin it to the bottom and make it grow. Actually, no. We don't want to make it grow. All we want to do is pin it to the bottom. It's going to stay the same size. All right. With this, save it. That's all we really need to do. Let's go back to Xcode. Run again.
And again, this one rotates nicely. Still, I haven't broken it yet. Press chocolate cake and rotate this one. As we can see, much better layout in here. So let's take a look at the next one. Except apparently I-- I made it a little too small. Let's actually go ahead and fix it, 'cause this isn't right. Let's go back to Interface Builder, and let's just actually just make this a little bigger.
Let's rotate. Yeah, better this time. All right. Rotating back. Let's take a look at the photo view controller. Let's view the picture. Looks pretty good in this orientation. Let's rotate it. Again, not quite right. Let's go ahead and fix it. Again, this is the one view controller we set up entirely in code, so this is going to be a little bit different.
In the recipe for the view controller, Again, in the load view method, we're creating this view. What we need to do here is set the autoresizing masks. So we're going to set the autoresizing masks to flexible height, flexible width, so that it grows with its container view, its super view.
Next thing we're going to do in addition to that is actually set the content mode for the UI image view. This is the property of the--
[Transcript missing]
There we go. We have the image. When we rotate, there we go. It rotates, scales properly, and everything. And when I go back, Everything's there in the right orientation. All right. And that's all you need to do to get rotation in the recipes application. Back to you, Evan.
So as you can see, using view controllers in your application makes it really easy to support rotation. Trust me, there's a lot of nasty geometry that goes into making rotation work nicely, and if you can avoid writing that code, that's a big advantage. We'd like to continue extending the Recipes application.
So in the session after this one, in this same room, we're going to add some table views to the Recipes app. So at the top level, we're going to have a list of recipes. And at the recipe detail level, we're going to add a different type of table view that allows us to display the ingredients and other types of data more effectively to the user. So I'd really encourage you to stick around and check this session out.
And then on Thursday, in the Mastering iPhone View Controller session, we're going to cover some more advanced topics with view controllers. Specifically, we're going to customize the navigation bar at the top of the screen, and we're going to combine the navigation and tab bar application flows. So this is a really common way to build a really complex, full-featured application. And there are some other features which we're going to add, which you can't currently see here, but I really encourage you to all come and check it out.
So that just about wraps things up. I'd really like to encourage you all to embrace the concept of a screenful. If you do this, it's really going to help you to craft a great iPhone application user experience. And remember, view controllers are your building blocks for your app. Using view controllers to manage a screenful of content is much easier than just figuring out a way to do it yourself. And it makes it much easier to maintain and manage and extend your code.
And finally, it allows you to adopt common application flows without needing to roll your own. And this isn't just for, you know, simple demo test apps. You know, we actually use this in the applications that we ship at Apple. The iTunes Music Store is one example of this. It's an application that was developed using view controllers from the ground up.
And this app was developed by a single engineer in a really ridiculously short amount of time. And to be fair, he's a really smart engineer, and he was working like 32 hours a day. But he was able to focus on what made that application unique rather than reinventing the wheel. And you can reap the same benefit in your application by using view controllers.
So I'd encourage you to, if you have more questions that you can't get answered here at WWDC, to talk to Derek Horn. I wanted to include a map to his house here, but he wouldn't let me. You can send him an email, or you can also check out the view controller documentation on the iPhone developer website, and that has some really great info on the topics which we just talked about, as well as some more advanced areas of view controllers. And again, I'd like to plug some sessions. The table view sessions, the understanding one is this afternoon, and the mastering table view session is on Friday morning. And also, mastering iPhone view controllers, we're going to cover some really cool topics with view controllers in your app.
And on top of all that, we've got a couple of view controller-specific labs. So if you've got code and you're using view controllers in your app and you've got questions, drop by, bring your code. Alex and I are going to be there along with a bunch of other engineers, and we can help answer your questions. So looking forward to see you there.