In this second part of a two part series, go beyond the basics in understanding how to make your apps adaptive. Learn through practical examples how to extend your application interfaces using UIKit. Get introduced to best practices for structuring your app for flexible interface designs. Learn from the experts what to keep in mind as you build apps for the future, today.
My name is David Duncan.
And along with Kurt Revis we'll be talking to you today
about making your apps adaptive.
So, in the first part, you got to see the tools
that Interface Builder has added as well as the foundation
on how you can do adaptively.
But in this part, we're going to talk to you more
about techniques that you can use to help make adaptive apps
as well as code that you can write
to build your own experiences while still remaining adaptive.
So, let's look at the agenda for today.
The first thing we're going to talk to you
about is just some basics on sizes and size classes just
to refresh everyone's memory.
In addition, we're going to talk about things that already exist
in UIKit in the Tools that can help you along
with Interface Builder and so you get the most out of UIKit.
And finally, Kurt's going to come up and talk to you
about how you can go beyond size classes
to build your experiences.
And so with that, let's begin with sizes.
If we go ahead and bring all of our devices
and their orientations and their adaptations up on screen,
that's pretty complicated-looking set
I don't think anyone wants to put all of those up,
figure out what their layouts look like and make that work.
So let's see if we can draw a diagram
to simplify what all of this looks like.
Well, that's still pretty complicated.
And I don't want you to read
that because there's a lot of text in there.
And it's really hard to read.
So let's see if we can get rid of all that text
and color and make it simpler.
And it's not really helping.
So, what else can we do?
Well, when we thought about this
in UIKit we thought what are some good places
that we can divide this space
up to create good experiences for users?
And as you might have guessed already, what we're talking
about are size classes.
We split the grid up and we split it
up into the compact width and regular width,
compact height and regular height.
And what we decided was that when you're
in the compact space, you have a more iPhone-like experience
where you try and make the best use of space.
But in the regular experiences, you want to be able
to do more advanced things, more interesting things
with that space that really takes advantage of it.
And so that take away from that is
that when you see a regular size class, that's your opportunity
to make a really great experience for the user
with that space, going beyond what you might do
in a compact space.
So, let's take a look at what UIKit already does
for you based on size class.
Most views and controls don't actually change.
So, you take a look at that switch.
It's the same whether you're in compact or regular.
That nav bar is also the same whether you're
in compact or regular.
But what things do change?
Well, here's a presentation.
It looks like it's a full screen presentation.
It's on a iPhone 6s Plus.
But, if we rotate and put the device
in compact, we see a form sheet.
And so one thing you see is that in presentations,
if you do a form sheet presentation
in regular size class, if you move to a compact size class,
we don't have enough room for it.
And so we change that to a full screen presentation.
Now, the thing in UIKit
that does most complicated adaptations based
on size classes and space available
Again, we're looking
at a compact width experience on an iPhone 6s Plus.
And you see that, as you might have typically experienced,
you just got a navigation controller
where we push and pop things.
But again, if we rotate and go into compact width,
we bring in the sidebar.
And we think that on an iPhone 6s Plus with all of that room
in regular width that having
that side bar is a better user experience than not.
Even though we only have so much room for it.
Similarly on iPad, the 9.7 inch iPad in landscape,
you can see that we keep that sidebar up as well, allowing you
to easily switch between mail messages.
But what do we do when you rotate to portrait?
Remember, on an iPad, it's still regular width.
But we've decided that on iPad you typically have content
that is much larger, much more interesting, images inline
and so forth, and you need that extra space
so that you can still interface with your content.
However, we allow you to slide in the sidebar
so you can still easily switch between email messages.
And so those are some things that we do in UIKit in order
to give you the best experience based off both size classes
and the actual amount of space available.
And in order to take advantage of that,
let's look at some best practices in UIKit
to make the most out of what you have.
So, we're going to speak to some things in Xcode Tools in UIKit.
And in the first part, you saw Interface Builder's enhancements
to building adaptive applications.
Being able to easily make adjustments based on size class
in gamut and other traits.
But, Xcode also provides Asset Catalogs.
And Asset Catalogs are great,
not just for organizing your images, but also specifying when
and how they should be used.
And of course, UIKit has lots of technologies
that make building adaptive apps easier.
We've been talking about Auto Layout for many years.
There are many sessions on it if you should,
you should go review those.
And of course, there's a session later today
on New Things in Auto Layout.
And trait collections were reviewed
in the first half as well.
But other things are Dynamic Type,
which allows your application to adapt to the font size
that users want to use.
Layout Guides are a great way
to pass Auto Layout information down the hierarchy.
And we're going to discuss some of the layout guides
that UIKit provides by default.
And finally, UIAppearance is a great way
to declaratively specify how you want your applications,
controls and views to look.
So let's go ahead and start with Asset Catalogs.
Asset catalogs allow you to adapt images automatically based
on the trait environment that they're displayed in.
And here's a small example of it.
So we've got our picture of baby Sophia here.
And we have 1, 2 and 3x versions of that image.
So that whether you're on an iPad 2 or an iPhone 6s Plus,
you can get the best possible image
for the resolution of the device.
But another advantage of it is
that Asset Catalogs lets you design for application thinning.
And what that means is is that if I deploy this application
to an iPhone 6s, which is a 2x device, I don't have
to pay the space penalty for carrying those 1
and 3x images as well.
Similarly, we'll also trim based on size classes in Gamut
and a few other things.
So, use the Asset Catalogs
and you can make the best specification for your images
and carry the least amount with you
when you actually deploy to user's devices.
Other things that Asset Catalogs provide are pieces of metadata
that you can attach to your image for various purposes.
And the first one we're going to discuss are alignment insets.
So let's bring baby Sophia back here.
And let's say that we have an application
where sometimes we actually want
to crop this image to a square crop.
And if we just naively pick the center part of the image,
we'd miss most of her face.
We really do want that square that frames her face well.
Now, what are you going to do?
Well, you're going to bring in some measurements and figure
out how far are you away from all of the edges?
But, instead of having to put it in code and associate it
with assets, you can do that directly in the Asset Catalog.
And UIImage will vend those values back
to you whenever you need them.
And similarly, of course, you can create images with them.
But being able to put them
in the Asset Catalog means you don't have
to have a giant table associating resource names
Similarly, let's say that you have some kind of background
for a table view or what have you that you need to be able
to resize to adapt to whatever size it's actually displayed at.
Well, you can create a nine-part image, creating slicing edges,
and store those in your Asset Catalog as well.
And then, when that image gets sized to its final state,
it resizes nicely without having carry
around large images specifically for the sizes
that you're working with.
And so, that's for Asset Catalogs.
Let's talk about other adaptations that you'll want
to make for your application with Dynamic Type.
We love Dynamic Type.
It gives our users the ability to specify font sizes,
and especially for our users that need a little extra help
with vision, they can specify really large sizes
that allow them to easily read text.
And so this year, we've made it even easier for you
to adopt Dynamic Type in your application.
And we've done this in two ways.
The first, we made it part of the trait environment.
So you don't have to listen for a notification anymore.
It's just right there for your custom text views
to take advantage of if you need it.
But we figured you shouldn't have to do
that for regular text views, for labels,
text fields and text views.
So we've made those really easy to do.
All you have to do is assign the font with the style
that you want and set the flag that adjusts the font
for the content size category.
All your labels, your text fields, your text views,
they'll automatically adapt to the current Dynamic Type size
and you don't have to do anything.
So of course, if you're to adopt this,
be certain to test your application
in all the Dynamic Type sizes.
As I mentioned, there's some really large ones.
The Accessibility Inspector on your Mac can connect
to your application and allow you to toggle back dynamically
without having to go back and forth between settings.
And if you're displaying these in table or collection views,
you'll want to review the "What's New
in Collection View" session,
because there's some really great information on performance
and behavior enhancements in collection view
that you can take advantage to make this really great.
And so, let's talk about Layout Guides.
And UIView provides two layout guides,
a Margin Guide the Readable Content Guide.
And we'll go through those in turn.
Both of these start out with a view.
Whatever content you happen to have it in.
The Layout Margins Guide is defined in part
by a property UIView that is the layout margins,
which defines insets on all sides.
And so, how do we then create a layout guide?
Well, that's just a rec specified in terms of that view.
And that Layout Margin Guide, of course,
provides auto layout objects for you
to generate your own constraints on.
Simple. So, what's the Readable Content Guide
in relation to this?
The Readable Content Guide is a guide that provides you
with information on how to layout text
so that it has a nice, readable line length.
If you're on one of the new 12.9 inch iPad Pros,
you can layout text from side to side and your users will kind
of being turning their heads as they're reading it.
So, the first thing we want
to calculate is what is the ideal width for a line of text?
And then, of course, we don't want the text
to flow outside of the margins.
So we bring in that margins guide
as part of our calculation.
And we combine these two
to finally form the readable content guide,
another layout guide within your UIView
that you can lay out text within.
Now, the Readable Content Guide is based
on the dynamic text size.
So, what happens when that changes?
Well, we increase the dynamic type size
and the ideal width increases.
And as you can see, because the readable content guide is based
inside of the layout margins,
the guide doesn't necessarily extend past those margins.
And then you can lay out your text
and get a nice readable length
of text that's inside of your view.
And so with that, let's talk about UIAppearance.
UIAppearance, if you haven't used it, is a declarative way
for you to specify what your application should look like.
And what does that mean?
Well, that means that instead of writing code
when you see a new tab bar, for example, you write this:
You say, for all of my tab bars,
the appearance should have the unselected tint color is blue.
And that any time you create a tab bar,
unselected items are colored blue.
But it's also contextual.
And that means that you can specify based
on trait collections or based on the containment of those views.
And what does that look like?
Let's take a look.
So, here we have our little application.
And as is the style, we want to have a giant header image
at the top when we're in regular vertical height.
And we're going to have
that image just replace the nav bar's background.
However, when we're in compact vertical height,
we're going to have a side-by-side layout.
And the image is not going to necessarily extend
to the navigation bar.
So we want it to use its default background.
So let's do the default background first.
We create a TraitCollection for verticalSizeClassCompact.
We grab the navigation bar's appearance
for that TraitCollection.
And we say we don't want
to use any background image for that appearance.
And that will cause the navigation bar to fall back
to using its default appearance.
Similarly, when we do the regular vertical,
we create a trait collection for that, grab that appearance,
and assign an empty image, which will cause the navigation bar
to construct no background image whatsoever.
Now, you might note that the appearance API
for trait collection, that might read a little funny.
We're actually going to be changing that API for C2,
so be on the lookout for that.
And so with that, let's go ahead and wrap
up the best practices section
where we reviewed using Asset Catalogs
to organize your images.
Dynamic Type to adapt to the user's desire for the font size.
Layout Guides to help you build your own layouts in ways
that are easily adaptable to all of your layout situations.
And finally, Appearance
to get your application looking exactly like you want it.
And so with that, I'll hand it over to Kurt.
Thank you, David.
So, if you remember from "Making Apps Adaptive,
Part 1" you'll remember the takeaway message, which is:
The system is going to do most
of the work, so you don't have to.
Now, I'm going to talk today about how to go beyond that.
So, if you want to go beyond what the system provides,
here's how to do it.
And the operative word here is "if you want to."
This isn't required.
However, if you don't -- even if you don't take advantage
of this, you might learn some things about how
to work more effectively with UIKit.
So I'll talk about how to go beyond the basics.
I'll tell you how to design your app to handle all combinations
of device orientation and size.
I'll talk about how you can implement these designs
and change between them dynamically
as your app changes size.
And then I'll talk about using reusable elements
to make it quicker and easier to build your app.
And I'll do this in the context of an app.
We'll build a real app here.
So, I'll call my app My Incredibly Adaptive App.
And fortunately, it's also incredibly simple.
We've only got three things that we're going to show in this app.
Each one has a title.
Here they're just A, B and C.
And then there's a longer piece of text, a description,
that goes with each one.
So even though this app is very simple,
I'm going to use techniques that you can use
in your much more complicated and bigger apps.
So this is the model of my app.
This is the data inside of it.
But how should my app look and how should it act?
What's the design?
Well, when I'm thinking about these designs,
I need to consider all these combinations.
But that's far too much to do a unique design for each one.
That would be far too much work.
So let's try to simplify this.
I think in my app I can do it with just two designs.
I'll call the first design "Tall."
And I'll arrange these items vertically, A, B,
and C vertically in the stack.
My other design will be "Wide."
So I'll arrange these items horizontally.
Now, I think no matter what size my app actually is,
for my app I can use one
of these two designs and make them fit.
So now the question is: Given a combination
of device orientation and size,
how do I choose what design to use?
I need to define a rule for that.
And again, this is unique to my app.
I think I'm going to choose: If the width is less
than the height, I'll use the Tall design.
Otherwise, I'll use the Wide design.
Now, I can run through all these combinations
and see how it works.
I can do this on paper before I even start writing any code
So for instance, this iPhone in portrait, the width is less
than the height, we'll use the tall design.
Now, I can continue that with the iPhone in landscape
and with an iPad, full screen, or an iPad partial screen,
and go through all the examples and try them out
and make sure they make sense.
So I'll reiterate what I just did.
When I'm designing my app to hand these things,
I thought through all the combinations.
I came up with designs to cover all those combinations,
the whole range.
And then I defined rules to say which design to use.
So when I'm defining those rules,
there's many ways I can do it.
This is what makes my app unique.
But you'll note that I could have checked to see
if the size exactly matched certain things.
I could have seen is the size 1024 by 768,
therefore it's an iPad and made decisions based on that.
I don't want to do that because there's too many combinations
And those sizes will change over time.
So instead, I defined a simple Boolean condition
that would tell me what design to use.
And there's many ways we can do this.
The first one, and most obvious, is just use size classes.
Then we've done most of the work for you.
All you have to do is check are you compact or regular.
Also, your app will act like other apps in the system
because you're using the same size classes.
All the Xcode tooling will help you out.
You'll get a lot of things just for free.
But, you can also do it yourself.
For instance, I could compare a value like width
or height to a threshold value.
Or I could compare two values like I did, width versus height.
Or I could combine these.
The point is that I came up with a simple and unambiguous way
to figure out what design to use.
So another thing when you're thinking
about your designs is even if your size is the same,
you might be, say, on one side of the iPad or the other side.
So don't make your designs specific to where the buttons
on the device are, or where the other app is
if you're multitasking, that sort of thing.
I'll need to find the size of the app.
I'll need to use those rules to decide what design to use.
And then last, I'll apply that design to the UI.
So change the views of my UI to make a match.
Now, where should I put this code?
If I make a new template in Xcode, or new view controller,
it gives me this template with a viewDidLoad method.
And it says do any additional setup here.
So that's where I should put it, right?
Unfortunately, it's not that simple.
The reason you don't want to do this is
because views get loaded on demand.
The first time something asks for that view
in your view controller, this will get called.
And that's very early.
So we know at that time your view won't be
in a superview yet.
Layout wont' be valid yet.
So you really can't count on your view size
or any parent size or traits or so on.
It's just too early.
So for one-time only things like initializers, loadView,
viewDidLoad, you only want to put code that's going
to be the same across all of your designs.
A better place for me to put my code is
in a view controller's viewWillLayoutSubViews.
And we'll view that because
at that time the view is in a superview.
Layout of all those superviews has happened.
Sizes are valid.
My view size is valid.
Traits are valid.
And also, this is a good time to manipulate the things inside
of my view controller.
So this is where I should change this stuff inside my view
controller views and constraints and so on.
Now, it's important to be careful here.
Because this is a very hot path.
This is called very often.
Often, for reasons outside of your control.
So, do as little work as you possibly can in this method.
Ideally you would find out what's changed
since the last time it was called and then do as little
as you can to update based on that change.
So change only the attributes of views
that you absolutely need to change.
And then finally, be careful not to cause a layout loop.
If you invalidate layout of your superviews,
they might in turn invalidate your layout.
And soon you're finding that your app is doing but validating
and invalidating layout and nothing is actually happening.
So to find out more about debugging and finding
out about layout loops, check out the "What's New
in Auto Layout" session later today.
So, here's my two designs.
We'll go back to this.
How am I actually going to implement these things?
Well, I think I can do it with just a view
for each item, A, B, and C.
And then I'll us a UIStackView
to arrange these things horizontally or vertically.
UIStackView will do all the work for me.
I don't have to think too hard.
So here's some code.
My simple example view controller is a subclass
And I made a storyboard for this.
It's got a stack view in it
and it's already got those three views inside.
Now, I am going to,
in my viewWillLayoutSubviews method, I'll override that.
First step, get the size, which is view.bounds.size.
Second, apply my rules.
So if the width is greater than the height --
or equal to the height, I will choose to use the wide design.
And then finally I'll apply that design.
So, if I'm using the wide design,
my stack view's access should be horizontal.
Otherwise it should be vertical.
That's all I have to do.
So you'll note that here I'm not doing a lot of work.
And I'm also taking advantage of the fact
that StackView is smart.
If I'm setting the access to the value that it already had,
it's not going to do any additional work.
So let's see this in action.
Here's my app on an iPhone in portrait.
We've got that vertical layout.
And now if I rotate to horizontal,
we'll see that the app also rotates to horizontal.
And also I got this animation for free.
So I'll go back to portrait and I'll show that again.
There we are.
So, I showed this to David,
because I was especially impressed
that StackView gave me this animation for free.
I didn't expect that.
And he said, "Well, that's great.
That's pretty amazing.
But can you make it better?
Could you make it pop?"
And if you're an app developer, maybe you've heard this before
from one of your clients.
So I said, "Sure, I can make this pop."
I can make my app a little more interesting
and I'll make it pop here.
So I'll do this by, during the rotation,
I'll make the items grow towards you.
And then when I'm done, I'll make them go back to normal,
shrink back to normal.
Now, this isn't something that we necessarily advocate
that you do in your app.
Not this particular technique of making it pop.
But the point is where I'm putting the code
and where I'm exactly doing this.
So, I'm doing this code in viewWillTransition
to size with coordinator.
And I'm doing this because it will be called during an app
size change or a rotation.
And I'm giving this coordinator that lets me set
up animations alongside the rotation
and to happen afterwards.
Now, why don't I put all my layout code in here?
That's because this isn't called the first time
through when your app launches.
There's other reasons, but that's the main reason.
So I'll use the coordinator and I'll set up a block
to animate alongside the rotation.
And all I have to do in this block is set the parameter
that I want to be animated.
It'll go alongside the rotation
with the same curve and the same timing.
And I'm going to set that stack view's transform to a scale
up of a factor of 1.4.
So a little bit bigger.
Then when I'm done, I get to set
up my own animation with my own duration.
Here I'm picking .5.
And we'll go back to normal.
We'll set the affine transform back to the identity.
So back to normal.
So here we go.
Here's the same app just with that additional code on there.
And it popped towards you and went back.
If we rotate again, it will do the same thing.
So there we go.
I got to add that pop effect.
I got to make it a little more interesting.
But I didn't have to change my core layout code.
It remained the same.
So I just added it on top.
So the last thing I'd like to talk about is reusable elements.
And this is a way that you can build your app out of pieces
that can be reused across different designs.
This way you can build you app more quickly and take advantage
of these different designs without having
to rewrite everything.
We'll do this by using view controllers.
Each piece will typically be a view controller.
And that's because they package up a lot
of useful stuff all together.
For instance, you get a whole tree of views,
not just a single view, but a whole tree of views
and all their constraints that go with them.
You get to make connections to other view controllers.
So you might perform a segue to different view controller
or present something, find your parent view controllers
and so on.
And also, it's a place to make connections
to the rest of your app.
So you might have a connection to model objects or an object
that represents network access or so on.
Now, the view controllers in your app are going
to perform different roles.
You might have a container view controller.
And it might contain multiple contained view controllers.
Now, you're probably used
to writing contained view controllers
and then putting them in containers that UIKit provides.
For example a navigation controller
or split view controller or a tab bar controller and so on.
But you can write your own container view controllers.
And this lets you really unlock a lot of power.
You can do a lot of things with that.
So I'll show how to do this.
Here's my designs again.
And in my case, I think I can have an outer container view
controller that I'll call ExampleContainerViewController.
And inside of that I'll have three element view controllers,
one for each one of these things.
Now, thinking about it, I think I need a little refinement
to my design.
So if I don't have much space, I'm going to need
to show just a preview of these items.
I don't have room for the full text, just the title.
So, when I click on one of these items, or excuse me,
tap on one of these items, it's going to be a preview.
I will present another view controller
that shows the full text.
Then when I tap on that thing again,
we'll dismiss it, it'll go away.
So I'll do this by having my ExampleContainerViewController
will have three small element view controllers.
I'll define this later.
When we present one, when we tap on that thing, we'll create
and present a new large element view controller.
Now, if my app is big enough, I don't have to do all that.
I'd like to just show the large element view controllers right
here directly in that container.
So my container will just have three instances
of another class LargeElementViewController.
And when the app size changes dynamically,
we'll change the view controller hierarchy to go
between one of these two states.
So I'll show the code here.
We're going to work our way
up from the contained view controllers into the containers.
So we'll start with the storyboard
for these contained view controllers.
And it's pretty simple.
We've just got a simple view with the title here.
You'll note that I set the custom class
to be SmallElementViewController.
And I also set the storyboard identifier to small element.
This way I can find these things in the storyboard
and instantiate them later.
For the LargeElementViewController
It's got that extra text in it.
The same idea.
I set my custom class to LargeElementViewController.
And I set the identifier.
So here's the code for the SmallElementViewController.
We'll start with this.
And I know that every time I show this I'm going to want
to tap it to show the large one.
So in my viewDidLoad, this is an appropriate time to do this,
I'm going to set up my tap gesture recognizer
and add it to my view.
Later, when that thing is tapped, this will be called.
We'll go on and find our main storyboard and instantiate
that LargeElementViewController using the
Finally, all we have to do is present that then.
In the LargeElementViewController,
it's a little more tricky because we need
to know are we being presented or not.
If it's being presented, we need to tap to dismiss.
If it's not, we don't.
So I'll put this code in viewWillAppear.
I'm doing that because I can use this other method
isBeingPresented to find out am I being presented or not.
So if it is, then I add the tap gesture recognizer,
the same way as before.
When that's tapped, all I have to do is dismiss.
So now let's get on to the ContainerViewController.
And I'm going to add an additional object
to make this easier to work with.
We'll call this the design object.
And the design object is really going to wrap
up all the information that describes what a design is.
I'll make it an immutable struct for safety.
So I can write a function that returns one of these,
and after it's been returned, it won't change.
Nobody can change it.
And then finally, I'll allow comparisons.
So I can see is my design that I want to use different
than what I'm currently displaying.
So let's actually implement this.
I've got just a simple Swift struct here.
It's going to have two pieces of information in it.
The first one is the axis.
I'm reusing this enum from stackView,
so it's either vertical or horizontal.
Then I'm going to define my own enum
for whether I'm using the small version or the large version
of the view controllers inside.
I call that elementKind.
Finally, I've got a read-only computed property here
And this just tells me what identifier to use
to make those view controllers from the storyboard.
Finally, I'll implement the Equatable protocol from Swift.
This is just function equals equals.
And I just compare the data inside my two designs
to see if they're the same.
So finally, let's get up into the container view controller
and actually do this stuff.
You'll remember it's going
to have three child view controllers.
It's going to use those rules to create
and decide what design to use.
And then finally we'll update.
Every layout will reevaluate what design to use
and change things if we need to.
So here we go.
I've got an array with these three slots
for three optional view controllers.
And they start out as nil.
Because when this thing is initially created,
nothing is going to be showing there yet.
I'll also keep track of the design
that I'm currently displaying.
And also that's optional and it's nil
because nothing has happened yet.
So, in my viewWillLayoutSubviews,
this should look very familiar by now.
I'm going to get my size.
I'm going to call a function called decideDesign based
on the size, return a new design to use.
And if that design is different
than what I'm currently displaying,
I'm going to apply that design to my UI.
So change my UI to match.
So you'll note this exactly like the pseudocode
that I talked about earlier.
And really, no matter what your app does,
you can probably follow this same pattern.
You'll have different stuff in your design.
and applyDesign methods will be different.
But you'll probably be following this exact same pattern.
So let's fill in these functions from my sample app.
decideDesign will first decide on the axis.
And we've already been over how we did this with this rule.
For the elementKind I'm going to use a different rule.
So I'm going to choose if my app's width is less
than a threshold, choose to use the small ones.
Otherwise use the large ones.
And here I'm just comparing against a constant.
This is just an example that I'm using for my app.
This isn't a value you should necessarily use in your app.
It's just an example.
Finally, I'm going to wrap up those two pieces of information
in a design object and return it.
To apply a design, I need to apply those two things.
So I need to find out if they've changed.
So again, for the axis we'll just pass
that directly to the stack view.
It won't do anything if doesn't need to.
For the elementKind, we've got more work to do.
If we have old element view controllers
and the element kind is changing, then we need
to destroy the old ones and create new ones.
So here's how we'll do that.
We'll iterate through that array.
And I'm using this enumerated function here
because it lets me get the index and the object
at that index simultaneously while I'm iterating.
And finally, if we've got an old element view controller,
then I need to remove it.
I'll call this function to remove it.
Go to my storyboard, create a new element view controller
using the identifier that the design gave me.
And then finally call a function to add
that new child view controller.
And then save it in the array for the next time through.
So, last slide of code.
Thank you for sticking with me.
These are some things that we need to do
to be a well-behaved container view controller.
So it's important to do these steps in this exact order.
When we're adding a new view controller,
we first call addChildViewController.
This adds that view controller
as to self's list of view controllers.
Then we need to add that new view controller's view
to the view hierarchy.
We do this by using the stack view's
And UIKit doesn't do this for you.
And in fact, can't do it for you because we don't know
where it's going to go in the view hierarchy.
Only you can tell us that.
Finally, once that's done,
you tell that view controller it did move
to a new parent view controller, and that's "self".
To remove the old one, we do much the same steps,
just in the opposite order.
So we tell it it will move
to a new parent view controller, which is nil.
Remove its view from the view hierarchy.
And then finally, remove it from self's list
of child view controllers.
So here we are.
I'll actually show you the app, finally.
Here we are on the iPad in landscape.
We've got lots of room.
We're using that horizontal layout
and we're using the LargeElementViewControllers.
Now, if I slide over another app
and pin it, my app's now smaller.
I switched to that vertical layout.
But I'm using those LargeElementViewControllers
In fact, they're the same instance of the view controllers
that we were looking at earlier.
Now, if I make that app smaller still,
you'll note that we switch to that smaller design.
So we're still vertical.
We are using that smaller design.
I can now tap on one of those small view controllers,
present the large one.
If I tap again, we'll dismiss it.
So there's my app.
You'll note that we went beyond the basics.
We really decided exactly what we wanted to do by ourselves.
I handled designs of all those combinations.
I implemented each design.
We changed between them dynamically
as the app changed size,
and also used reusable elements to do it.
So my app is an example of this.
Your app can do all these things, too.
So now we've been through the basics.
We've shown you what Xcode can do.
We've shown you some of the incredible things
that UIKit provides in this whole Swiss Army knife of tools.
And we've been through code in a real example app.
So, we've really barely scratch the surface here.
There's a lot more to go.
So, check out our sample code at this URL.
Also, if you didn't see Session 1, please review that.
There was a great talk about inclusive app design
that talked about typography.
New stuff in Collection View and Auto Layout
that David mentioned earlier.
And then also the last two years at WWDC we've talked
about adaptive apps and multitasking.
And we really didn't duplicate too much of that material.
So, please review that stuff.
There's a lot of great material in those talks.
So thank you.
Have a fantastic Friday.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.