WWDC2014 Session 228

Transcript

X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Applause ]
>> Good morning.
My name is Jim Turner.
>> And I'm Peter Hajas.
And we're engineers
on the UIKit Team.
>> And welcome to
the presentation
on A Look Inside
Presentation Controllers.
>> So UIViewController
presentations have been
around since iOS 2, but only
recently have you had the chance
to customize them in your apps.
In iOS 7, we introduced the
concept of an animator object.
This is an object
who's responsible
for animating your view
controller's content on-screen.
However, if you wanted to build
a totally custom view controller
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
However, if you wanted to build
a totally custom view controller
presentation, it involved
burdening that animator object
with far too much
responsibility.
>> So that's why in iOS 8,
we're introducing
UIPresentationController.
This class is designed to work
in concert with animator objects
to make the job of presenting
view controller content easy
and simple to manage
and execute.
So today, we're going to talk
about just a couple of topics,
the first being some
presentation basics.
What do we mean by presenting
view controller content?
What's the difference between
chrome and content itself?
And what do we expect
UIPresentationController
to be responsible for?
Next, we'll go over how UIKit
used UIPresentationController
to expand our own API.
And finally, we'll
wind up with a demo
that brings all these
concepts together,
so that you guys can see how you
can use UIPresentationController
in your apps.
>> First, let's start with
some presentation basics.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> First, let's start with
some presentation basics.
Here I am, on the Settings app
on iPad, and I'm going to tap
that Create New Apple
ID table cell.
The New Account sheet slides
up, and we're ready to go.
In UIViewController
terminology, we would call
that New Account Sheet the
presented view controller.
And the Settings
split view behind it,
the presenting view controller.
When we talk about
the responsibilities
of UIPresentationController,
we would say
that that New Account Sheet is
the content of the presentation.
It's the foreground stuff
that your user is
meant to interact with.
We would then say that the
background content that's dimmed
is the chrome.
It's dimmed to help
accentuate the content
of your presentation.
To help manage the
content and chrome,
in your view controller
presentation,
we're going to use
UIPresentationController.
At its heart,
UIPresentationController is the
presentation management class
that you'll use in
your application.
All UI view controller
presentations
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
All UI view controller
presentations
in iOS 8 are backed by
UIPresentationController.
Because UIPresentationController
can provide chrome,
it can also provide its own
animations for that chrome or --
and this is really cool --
UIPresentationController can
animate its chrome alongside
your existing animator
objects' custom animations.
And we'll take a look
at a demo of that.
Additionally, throughout
the conference, you've heard
about our push to make your
applications more adaptive.
And UIPresentationController
is built from the get-go
to handle trait and
size class changes.
Additionally,
UIPresentationController will
respond to these changes,
even while your view
controller's presentation
is on-screen.
So you can adapt seamlessly
between the changing
environment.
And finally, because
UIPresentationController is a
great Cocoa Touch
citizen, it's reusable.
UIPresentationController
objects are not coupled
to animator objects or
transitioning delegates.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to animator objects or
transitioning delegates.
You can use the same
Presentation Controller
with different view controllers,
or switch out the
Presentation Controller
for the same view controller
to create a truly custom look.
>> Prior to iOS 8, the animator
object, as Peter mentioned,
was kind of overburdened
with some tasks
when presenting a view
controller's content on-screen.
Its primary task was
obviously animating
that controller's content,
and that includes any kind
of subview animations --
things like content
offsets or insets, as well.
But it also needed to figure out
its own positioning on-screen.
If you were doing any kind
of custom presentation,
we would give you reasonably
good information for where
to start and where to end,
but it's probably
not what you wanted
for your custom presentation.
And so the animator
object had to know more
about the presentation than
it probably should have.
And that goes along with
the chrome, as well.
That animator object also needed
to know, the entire layout --
what the presentation
was going to encompass.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
what the presentation
was going to encompass.
But now, with Presentation
Controller, this responsibility
for positioning that
view controller
and for handling the chrome
and other views that go along
with the presentation
are handled
in a much more logical object.
The Presentation Controller --
and since it's long-lived --
knows more about
the presentation,
because it has a
better vantage point
for what's actually
going to occur on-screen.
And as we have mentioned before,
Presentation Controller
is what drives adaptation
in your application.
This object is going
to be responsible
for helping you switch
out view controllers
and wholesale switching out
of Presentation Controllers,
which we will look
at in just a moment.
So now that we know about --
a little bit about what
Presentation Controller actually
is, let's show you how
we in UIKit used it
to improve popovers, alerts,
action sheets and search.
And we'll have Peter start
you off with popovers.
>> Sure thing.
As you saw in our
talk yesterday,
we're introducing a new
UIPresentationController class
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
we're introducing a new
UIPresentationController class
to help manage popover
presentations in your app.
It's called
UIPopoverPresentationController.
It's intended to replace
UIPopoverController
in your application, but it
is functionally equivalent
in the customization that it
provides for the presentation.
But it has some additional
features.
It has built-in adaptivity
to help facilitate your
view controller adapting
in a changing environment.
UIPopoverPresentationController
will seamlessly handle
transitions between regular
and compact-width environments.
Let's look at how you used to
show a popover, prior to iOS 8.
With the old API, you'd create
your content view controller,
set it on your Popover
Controller
and present that popover.
But this isn't really
the whole story.
If you had a universal
application --
and many of you do --
you actually had to
have two code paths.
We check for it on an iPad
and make a popover controller.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We check for it on an iPad
and make a popover controller.
Otherwise, we'd do a
presentViewController
traditionally.
And you had to litter this
bifurcation throughout your app.
With
UIPopoverPresentationController,
you'll just have one code path.
Here's how to use it.
First, you'll set
the view controller's
modalPresentationStyle
to popover.
This is a new value in iOS 8.
UIKit will look to
your view controller's
modalPresentationStyle
to determine how
to show your view controller.
Then you'll get its
popoverPresentationController.
When presenting a
view controller,
you do not create a
Presentation Controller.
Instead, you ask for one.
Then you set up any source
information, like barButtomItems
or permittedArrowDirections.
And because it's a view
controller presentation,
you just call
presentViewController.
Now, notice how there's no
idiom check on the screen.
That's because, when we're
running an environment
that does not support
popovers, like on the iPhone,
UIPopoverPresentationController
provides the opportunity
for your presentation to adapt.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
for your presentation to adapt.
Jim, can we take a look
at adaptive popovers?
>> Sure.
All right.
So I have a fairly simple
and basic application here.
It is a -- just a
view controller
that shows important people and
-- the super important people --
and you click on this little
button here, you get a popover.
And it's a popover of
super important people.
And so what we want to do
is show that this popover,
when it goes on -- in a
compact-width environment,
like on the iPhone, even though
you present as a popover,
you will get an adaptation to
an over-fullscreen presentation.
So we'll change the
width to 320,
and we'll change the size class
to compact, and we'll apply it.
And then, now you see
that we actually have --
the same table view has been
re-presented, but now it's
in a view controller that is
a full-screen presentation.
And we can actually
even dismiss this,
and we can re-present it again.
And even though we're
re-presenting
as an over-fullscreen
presentation, we are --
the code has never changed.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
the code has never changed.
We still actually are
presenting a popover here.
And to show that that's
actually still working,
we'll go back to
our regular width.
And then the popover
shows back up again.
So to do adaptivity with
popovers is fairly simple.
Going back to Peter's code
that we left off with is
that this code doesn't
actually change.
All through that,
this was the code
that presented that popover.
But to influence how the
popover actually works,
we need to set a delegate on the
popover Presentation Controller.
And we need to implement
just two methods.
The first is
adaptivePresentationStyle
ForPresentationController.
And from this method,
you can return one
of three different methods --
FullScreen, OverFullScreen,
or none -- the latter meaning
that you don't want any kind
of adaptivity, but for here,
we want to do a FullScreen
adaptation.
The second method that we want
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The second method that we want
to implement is
presentationController
viewControllerFor
AdaptivePresentationStyle.
You don't have to
implement this method.
And if we hadn't
implemented this method,
the table view controller
would have been re-presented
as a full-screen presentation.
But the table view by
itself doesn't allow you
to dismiss anything or show the
name that we were selecting.
So what we want to do is
wrap that view controller
in something that
allows our presentation
to actually continue to look
like how we wanted it to look.
And so we wrapped that in
a NavigationController,
and we just set it as
root view controller,
the presentedViewController,
which was our table
view controller.
And that's it.
And that is how you get from
a popover in regular width
to an over-fullscreen or
full-screen presentation,
when you're in a
compact-width environment.
>> So now that we've looked
at how UIKit used
Presentation Controllers
to improve the API
surrounding popovers,
let's talk about something
near and dear to my heart:
alerts and action sheets.
Prior to iOS 8, alerts and
action sheets were exposed
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Prior to iOS 8, alerts and
action sheets were exposed
to your application through
plain UI view subclasses:
UIAlertView and UIActionSheet.
But because they were
UI view subclasses,
they had to re-implement
some of the logic
that we already had
on view controller.
For example, to appear
in your application,
they created a new window,
strategically positioned
above your application's content
so that they'd show
up above everything.
Additionally, they'd pre-date
modern language features,
so they had to rely on delegate
API for button callbacks.
Let's look at how an action
sheet presentation worked prior
to iOS 8.
So, I'm in an iOS 7
app, in landscape.
And I go to show
an action sheet.
Behind the scenes, the
framework creates a window
on your app's behalf, but this
predates iOS 8 window rotation
behavior, so this window is
technically still in portrait.
We then add the action
sheet to that window
and mimic the transform
hierarchy of the presenting view
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and mimic the transform
hierarchy of the presenting view
to get into the right
orientation.
When looking at the requirements
applications would have to meet
when implementing adaptivity and
the customization power offered
to us by
UIPresentationController,
it was a natural choice to
rebase modern alerts API.
In iOS 8, we're introducing a
new View Controller subclass
to replace Alert View and
Action Sheet UIAlertController.
It's used for both
Alerts and Action Sheets,
and you can switch
via a preferred style.
Additionally, because
it's got a modern runtime,
it's block-based.
So it works perfect.
[ Applause ]
It works perfect with blocks in
Objective-C and closures in SWF.
Additionally, because
it's a view controller,
it presents in your window,
which means that
there's no more ambiguity
about what framework-provided
presentations are going
on in your application.
And using the adaptive API
that Jim showed you earlier,
action sheets will
seamlessly adapt to popovers,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
action sheets will
seamlessly adapt to popovers,
using
popoverPresentationController.
Let's go through
how you can create
and show an alert controller
in your application.
First, you'll ask for
one via the class method.
Then you'll add actions to
it with a block handler,
to handle when that
action is tapped.
And then, because it's a
view controller presentation,
you'll just call
presentViewController.
Now, that we've seen how UIKit
used Presentation Controller
to improve alerts
and action sheets,
let's see how we did the
same thing for search.
>> Search on iOS 8 consists
primarily of two parts:
UI search bar and
UISearchDisplayController.
Both have been around in the SDK
since some of the earliest days.
And their creation was formed at
a time that was far more simple.
View controllers were
more of a suggestion
than the requirement
that they are now.
There was far less
translucency --
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
There was far less
translucency --
things didn't flow
underneath other things,
and there certainly wasn't
things like blur to deal with.
And so when you presented
search, it was very easy
for the framework to reason
about how search was going
to be displayed in
your application.
But when we were looking
at SearchDisplayController
and how it would react to
an adaptive environment,
we realize it had some
deficiencies that were going
to be very difficult
to overcome.
The first is that it provides
very limited configurability
for you guys.
It's great that you can
show your search results
in a table view, but a lot
of other things have happened
since iOS 3, that you can
show search results in --
things like collection
views and map views.
And SearchDisplayController
just simply can't handle this.
Second, SearchDisplayController
is not a view controller,
although it tries to act
like one really hard.
And as the view controller
system became more intelligent
and more robust,
as the SDK matured,
the SearchDisplayController
had a harder time trying
to understand your
intent when displaying.
And this left it to
have to actually guess,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And this left it to
have to actually guess,
in some situations, and it
didn't always get it right.
And finally -- because again,
it's not a view controller --
its presentation was
done via addSubview.
And to show you how
horrible this actually was --
if, in your application
this was your search bar,
with your content being on
the blue, and you tapped
that search bar,
SearchDisplayController
behind the scenes goes
and creates a content view,
adds a dimming view to it,
adds the table view to
that and then adds subview
to the SearchDisplayController's
container -- or content view --
or content controller's view.
At this point in time,
your application has a view
that it didn't expect
in its hierarchy,
and the framework is
trying to manage the fact
that that view was
probably a scroll view,
and things could move around
when we don't want it to.
So it's clear that, in
adaptivity, this wasn't going
to really function
all that well.
But, while also looking at this,
SearchDisplayController's really
just doing a presentation.
I mean, it already
had its own container.
So it kind of made sense
to rebase this all on top
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So it kind of made sense
to rebase this all on top
of UIPresentationController.
And that's what we've done.
So in iOS 8, we're
introducing UISearchController,
which is a view controller-based
replacement
for the now deprecated
UISearchDisplayController.
And it has a number of
features, the first of which is
that it can present on any view
controller in your hierarchy,
not just ones that
are full-screen.
Second is that the
SearchController no longer tries
to get in between presenting the
thing that's showing the results
and the thing that's driving
the filtering of the results.
This means that any object in
your application that's capable
of filtering search results can
directly drive the UI that's
actually showing up on-screen.
You can influence the
search bar animation
through a custom
animator object.
And because, of course,
it's built on Presentation
Controller,
SearchController has the
capacity to become adaptive.
And what this means to
you guys, in the end,
is its far more control
in how search is display
in your applications and
far fewer assumptions made
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in your applications and
far fewer assumptions made
by the framework
when you're doing so.
So taking a look at how we
used to do this before iOS 8,
we would create a search bar,
and we'd give that search bar
to SearchDisplayController,
but then we'd have
to tell the SearchController
who the data source
and the delegate were
for the table view
that was going to
show the results.
And then finally, we
would make the search bar,
the table header view of a table
view that was already on-screen.
Now under iOS 8, with
SearchController,
the first thing you'll want
to do is create a
results controller.
And as I mentioned, this could
be absolutely anything --
a collection view or
maybe a view that's custom
to just your application.
You give this results controller
to the Search Results
Controller,
and then you tell the
SearchController who's going
to be responsible for
updating the results.
In a lot of cases, this
will actually just be the
results controller.
But it could be literally any
object in your application.
Next, this is the
one common code lying
between the old world, is
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
between the old world, is
that when you take the
SearchController search bar,
and we add it to the table -- or
set it as the table header view
of an existing table
view that's on-screen.
Now if you notice, we don't
actually present this view
controller at any point in time.
And that's because search
is usually event-driven.
The user is tapping on the
search bar, or they're tapping
on a search glyph
in your interface.
And so in those cases,
SearchController is going
to perform an automatic
presentation for you,
based off of where the search
bar is located at on-screen.
Of course, there's a delegate
method that allows you
to drive this, if you'd like.
But for the most part,
the default animations
are usually pretty close
to what you guys
are going to expect.
Finally is one piece of API
that's been on UIViewController
for some time, and its
definesPresentationContext.
When using UISearchController,
you're probably going to need
to define this on
the view controller
in which you want
search to be presented.
Because SearchController
is trying really hard
to play nicely with your
layout, it needs to know exactly
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to play nicely with your
layout, it needs to know exactly
where it is going
to be displayed at.
And definesPresentationContext
allows it to know
where you want it to go.
I'll show you in a real quick
example of what I mean here.
Take this example as a fairly
common case application.
As the application's root
View Controller is a tab bar
controller, and as that tab
bar's controller is selected
to tab, it is displaying
a navigation controller.
And the navigation controller's
root view controller is our
table view controller.
And as we've seen before
in the previous examples,
this search bar is that table
view controller's table view's
table header view.
And so, you probably want
it to have the same behavior
that you've seen before
iOS 8, is that when you tap
on the search bar, the
navigation bar disappears
and the search bar
takes its place.
And the search results take
the place of the table view.
In this example, the table
view controller needs
to define the presentation
context
for the SearchController.
If you were to omit this,
View Controller Presentation
behavior says that we will walk
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
View Controller Presentation
behavior says that we will walk
up the chain until
we find somebody else
who defines a Presentation
Context,
or we use the root
view controller.
And in this case, that would
be the tab bar controller.
And so this may actually be what
you want, but it's something
that you need to be aware
of when using the
new SearchController,
is that you need to tell
us where you want it at,
or we're just going
to go present it
on the root view controller.
So now that we've shown you
how UIKit is leveraged --
UIPresentationController -- what
are the benefits to you guys
for us having done this work?
Well, first off,
it's controllers now,
all over the place.
Everything's a controller
no matter where you look.
And this is good for you guys.
We are no longer trying to shove
their views into your hierarchy,
or we're no longer trying
to transform windows
above everything.
It's controllers.
It's a view controller system,
and it allows you very
unprecedented control
in how these control --
how these view controllers are
displayed in your application.
>> Additionally, because
UIPresentationController
provides an excellent
abstraction between the content
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of your presentation and
the chrome around it,
UIPresentationController
provides a natural home
for these things to live.
No longer do system-provided
view controllers contain their
chrome in the view controller.
>> And finally, adaptivity.
We keep saying this over and
over again, but we needed
to make our own controllers
adaptive for your guys --
for your guys' applications.
So now alerts and search can
adapt with your applications
and all the other
adaptations that you want to do
to make your applications work
in this new size class world
that we're going into.
So now that we've gone through
how UIKit has used these things
-- or used Presentation
Controller, let's show a demo
that kind of pulls all
these concepts together,
uses a custom Presentation
Controller and a custom animator
to make a really cool interface.
Peter?
>> Let's do it.
I've been working on this
awesome new photo management
and editing application.
Here we have a collection view.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Here we have a collection view.
And when I tap a photo,
we're going to do a View
Controller Presentation,
but it looks different
than a default view
controller presentation.
You'll notice that the
presented view controller slides
in from the right, while we
dim the rest of the screen.
And when we tap the dimming view
or hit the Save button,
we'll dismiss.
I'm going to edit
this photograph.
Looks great.
So I'll hit Save, and we
dismiss that view controller.
We should go through how this
presentation uses a custom
Presentation Controller
and animator object
to control placement
and animations.
Let's go through how you can
build a custom presentation
like this in your application.
We're going to start in the
root view controller of our app.
You'll notice this
P in the corner.
We've added colors
and text as a legend,
so that you know what controller
or object we're talking about.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
so that you know what controller
or object we're talking about.
In the root view controller,
we're going to create a new
overlay view controller.
This is what you saw,
presented as a side bar
in the demo we just saw.
Then, because it's
a view controller,
we'll just call
presentViewController.
Now if we had stopped here
and not implemented anything
custom, what would we get?
Well, we'd have our
root view controller,
and we go to present, and
we get the UIKit default:
a slide-up from the bottom,
full-screen presentation.
That looks cool, but what
we really want is a custom
presentation, so that when
we present the side bar,
it slides in from the right,
while we dim the presenting
view controller's content.
Let's talk about the objects
that are going to be responsible
for this custom presentation.
We already know that we
have a root view controller
and our presented
overlay view controller.
In iOS 7, we introduced
the concept
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In iOS 7, we introduced
the concept
of a transitioning delegate.
In this presentation,
this transitioning
delegate will be responsible
for providing the
animator object,
which animates our
controller contents on-screen.
This is the same API that
we introduced in iOS 7.
But new in iOS 8,
this transition delegate
will also provide the
Presentation Controller.
This is the object that
will drive the management
of the content and chrome
in this presentation.
Let's start with getting that
dimming view on- and off-screen.
First, back in our
root view controller,
we'll create a new
transitioning delegate to use
for this presentation.
This is the object that
provides the animator object
and Presentation Controller.
And we'll set that
transitioning delegate
on our presented
overlay view controller.
Now, in our overlay
view controller,
we'll set our
ModalPresentationStyle
to Custom.
This indicates to UIKit
that we should consult your
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This indicates to UIKit
that we should consult your
transitioning delegate for a
custom Presentation Controller
to use for the presentation.
Inside of our transitioning
delegate, we'll need to provide
that Presentation Controller
by implementing
PresentationController
for presentedViewController,
presentingViewController
source ViewController.
Here, we'll return to the
Presentation Controller
that will be responsible
for the lifetime
of this view controller's
transition.
Let's implement some methods
in the Presentation Controller
to manage this dimming view.
We're going to implement
two methods
to coordinate the dimming view.
The first is
presentationTransitionWillBegin.
This is called when we're
about to do the presentation
transition.
Here, we've already
set up a dimming view
in an int [phonetic],
and we'll just set
that dimming view's frame to
the container view's bounds.
This way, the dimming view
is always full-screen.
We'll also set the alpha
of the dimmingView to 0,
so that it appears
fully transparent
at the beginning
of the animation.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We'll make sure we
insert the dimmingView
above all the other
content in the presentation.
And then, this is really cool.
UIPresentationController can
provide its own animations
for its chrome -- in this
case, the dimming view --
or it can animate alongside
the existing animations
in the animator object.
And that's exactly what we want.
We call the
presentedViewController's
transitionCoordinator
to animate alongside the
current transition.
Inside of this block, we'll set
the dimming view's alpha to 1.
This way, the animations
both begin at the same time
and finish at the same
time, and it looks great.
Now, let's implement
the second method
in our Presentation Controller
for managing the dimming view:
dismissalTransitionWillBegin.
Here, we're going
to undo what we did,
and presentation
transition will begin.
In this case, we'll use the
same transitionCoordinator API
to animate fading the
dimming view to a 0 alpha.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to animate fading the
dimming view to a 0 alpha.
Let's see how this looks.
We go to present.
The dimming view fades
in, and it fades away.
Looks great, but we
should probably get our
presentedViewController
on-screen next.
First, we'll need to go back
to our transitioning delegate
and return a custom
animator object.
We'll do this by
implementing animationController
ForPresentedController,
presentingController,
sourceController.
This is the API that
you used in iOS 7.
Here, we'll return
our custom class,
which is in charge
of this animation.
We'll also implement the inverse
of this method -- dismissal --
or, I'm sorry
-animationController
ForDismissedController.
UIKit gives you the
power and flexibility
of using a different animator
object for the presentation
and dismissal, but here
we'll just use the same one.
Now, as you saw in the demo,
that overlay side bar was a
third the size of the display.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that overlay side bar was a
third the size of the display.
To size it appropriately,
we'll need to implement
several methods
in our Presentation Controller.
The first is
sizeForChildContentContainer
withParentContainerSize.
And this method's really simple.
We'll just return a third
of our parent's width
and our full parent's height,
so that we're always a
third of the display.
Next, we'll implement
frameOfPresentedView
InContainerView.
This is where we return
to the view controller
transitioning system what frame
we'd like the presented
view to have.
We'll use the same size that we
returned fromSizeForChildContent
ContainerwithParentContainerSize
and set the origin
of the presented view's frame
to be right-aligned
in the container.
Let's see how that looks.
Perfect. The overlay is a third
of the display and
right-aligned.
But what we also want is when
we rotate into landscape,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But what we also want is when
we rotate into landscape,
that side bar should
always appear
as a third of the display.
No problem.
Implementing rotation
in Presentation Controller
is really simple.
We just need to implement
one method:
containerViewWillLayoutSubviews.
First, we'll set the
dimming views frame
so that it's always the
full size of the container,
even when the container's
changing bounds.
Then we'll set the frame
of the presented view
to the same value we returned,
from frameOfPresented
ViewInContainerView.
And we're done.
We've handled rotation.
Now that we've seen how view
controller's sizing works
in Presentation Controllers,
it's important
to understand the
messaging that happens
between Presentation Controllers
and their managed
view controllers.
>> New in iOS 8 is a new
protocol, UIContentContainer,
and it's implemented by
both UIViewController
and UIPresentationController.
And it's a collection of methods
that describe how
the view controller
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that describe how
the view controller
and Presentation Controllers
communicate changes
in the environment
to one another.
And it's important that we talk
about these methods in regards
to how they flow between
each of the objects --
or between the controllers,
because the forwarding is
done automatically for you,
unless you interfere with it.
And I'll show you why
you'd want to do that.
There's a couple of different
ideas here, so we'll start off
with transitioning
to a specific size.
There's two methods
specifically here:
viewWillTransitionToSize
withTransitionCoordinator and,
as Peter just showed you,
sizeForChildContent Container
withParentContainerSize.
These indicate to
the view controller
or the Presentation Controller
that the physical size
of the view has actually
changed.
And this is best kind of
shown through a diagram
that shows how the
messaging flows through.
So let's give ourselves a root
view controller with a couple
of child view controllers,
and let's have it
present a view controller.
It doesn't really matter
what it actually is.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And as Peter has mentioned
previously, all presentations
of view controllers are managed
by a Presentation Controller,
so we've got to have
one of those guys, too.
So now that we have this set up,
let's give ourselves a
viewWillTransitionToSize call.
Maybe the device rotated, and
we're getting a different size
or different bounds
for that view.
These messages always start
with the root view controller.
And from there, that controller
will message any child view
controllers that it may have.
But the size that we pass
to the root view controller
is probably not the same size
that you want to
pass onto the child.
It's probably a smaller size.
So this is
where
sizeForChildContentContainer
withParentContainerSize
comes in.
We will ask the root
controller to size Child 1,
and that method returns
a size that we will pass
on to Child 1's
viewWillTransitionToSize.
We continue along if there are
any other child view controllers
of this controller.
And then any controllers
that are presenting
view controllers --
that means that they have
another view controller
presented on top of them --
will have their Presentation
Controller called next.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
will have their Presentation
Controller called next.
In this case, the root
view controllers --
the child view controllers,
excuse me --
aren't presenting anybody,
but the root view
controller actually is.
The root view controller
is not a container
for the Presentation Controller,
so the size that gets passed
to it is the same size that we
gave to the root controller.
But the Presentation
Controller is the container
for the presented controller.
So we need to ask the
Presentation Controller,
a sizeForChildContentContainer,
passing on to
presentedViewController.
The messaging flow is --
basically has a depth
for search.
You start with the
root view controller.
Any child controllers that
are present will get called,
but any controller
that is presenting a --
presenting another controller
will have its Presentation
Controller messaged and then
its presented controller
is messaged.
And then, the process
repeats again.
If for any reason that you
implement one of these methods,
and you call super,
this messaging still
is performed for you.
But if you implement these
methods and don't call super,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But if you implement these
methods and don't call super,
the object or the class that
does not pass the message on --
any of its child
controllers or any
of its presented Presentation
Controllers will no longer get
that message.
It's something to be aware of.
Oops, there was one more.
Next up is preferred
content size,
and there are two items
here: preferredContentSize
and preferredContentSizeDid
ChangeForChildContentContainer.
And this is methodologies
for allowing a presented
view controller --
or child view controller to
say, "I need more or less size"
to its container controller.
A really good example of this is
the Notification Center widgets
will do this.
Your notification -- your
widget will actually set its own
preferred content size, which
will message its container
to allow the size to change.
Let's show what this
looks like in our example.
Say the presented controller
wants to grow by 100 points.
So it sets its
PreferredContentSize
to what it would like.
And because the Presentation
Controller is the container
controller of the presented
controller, it gets the message,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
controller of the presented
controller, it gets the message,
PreferredContentSizeDid
ChangeForChildContentContainer.
Now, if one of the Child 1
or Child 2 view controllers
had requested more size,
then the root view controller
would have gotten this message.
So it's just messaging up
to the container controller.
At this point in time,
the container has
a decision to make.
Does it want to honor
the size request?
And if so, how much of
it does it want to honor?
It can simply ignore it, if
there's not any space to give.
Or it can say, "Well,
you asked for 100 points,
and I can give you 50."
If you were going to resize
the view, it's important
that you call back
viewWillTransitionToSize:
withTransitionCoordinator
back on the view
that made the request.
And this -- it's kind
of like a receipt
for that view controller, to let
it know that it requested size,
it's gotten a size, or however
much size the container gave it.
And it's allowed them
to forward that message
on to any child containers
it may have.
And key, right -- and
the key point here is
that after you've sent this
message, the container needs
to resize the child container,
the child view controller.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to resize the child container,
the child view controller.
Sending the message
ViewWillTransitionToSize does
not actually perform
the resize itself.
That's something that the
container needs to do.
Finally, our trait collections,
and there's one method here,
and that is
willTransitionToTraitCollection
withTransitionCoordinator.
And this has the same kind
of messaging semantics
as the ViewWillTransitionToSize.
It flows in the same order, and
if you don't call through super,
the message chain ends there.
If you hadn't seen
the talk yesterday
on building adaptive
applications with UIKit,
I highly recommend checking
that out, because it goes
into trait collections in
depth and how they interact
with the rest of the system.
But as a really quick
overview of what they are,
in case you haven't
read the documentation,
trait collections are simply a
collection of key value pairs
that describe an environment
to a view controller or a view
or a screen, and there
are four properties:
a horizontalSizeClass,
which describes width;
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
a horizontalSizeClass,
which describes width;
a vertical size -- excuse me --
a verticalSizeClass
that describes height;
the UserInterfaceIdiom that
describes the type of device
that you're on; and
then the scale
that decides the
scale of the device.
So for an iPhone, in portrait,
the horizontalSizeClass
is compact.
Its verticalSizeClass
is regular.
It's a phone, so it's
userInterface of phone,
and it has a scale of 2.0.
Now, all these methods
are trying to allow you
to have your application
respond to changes.
But some of you may be --
the ones that have been paying
attention most will probably
notice that we have two methods
that actually send somewhat
the same information.
willTransitionToTraitCollection
has the notion of size classes,
but we also have this method,
viewWillTransitionToSize,
that's sending along the size.
So why do we have
both of these methods?
That's a great question.
Before I actually tell you why,
I need to add two
more methods to this.
UIPresentationController's
containerViewWillLayoutSubviews
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
UIPresentationController's
containerViewWillLayoutSubviews
and UI View Controller's
viewWillLayoutSubviews.
Starting with
willTransitionToTraitCollection.
This is intended to be a
very coarse-grained control
over the layout of
your application.
When you receive trait
collection changes,
it's an indication
that the structure --
the overall structure of your
application is probably going
to change or needs
to be updated.
A great example of this
is, of course, adaptivity.
In that example demo I gave you
before, where the popover went
to full-screen, it's not just
a view being swapped out --
that is view controllers
and Presentation Controllers
being exchanged wholesale.
That's a significant
amount of change
to your application's
user interface.
But it's not just all
about size classes.
Screens could have
different scales.
Your view controller can be
on the main device screen,
which has a scale of 2x,
but then an external
monitor can have a 1x scale.
And moving that view controller
from the primary screen
to that secondary screen could
completely change how your UI
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to that secondary screen could
completely change how your UI
needs to be laid out.
And they're not --
it's not always
about entire UI changing
effects.
An example of this would be --
now in iOS 8, when we go
from an iPhone-like device,
and we go from a compact-width
regular height, and we rotate
into a compact-width,
compact-height environment,
we're going to auto-hide
the status bar for you.
And we do that not
because there's less space;
there's not less physical
space of that view controller.
It's that it makes more
sense in that situation
to remove a status bar, so
that your content has more area
to display itself.
Next up is
viewWillTransitionToSize,
and this is the medium-grain
control approach
for responding to changes.
And as I mentioned before,
this is an indication
that your view actually has
more or less size to deal with
and that you should
actually add more content
or remove content depending
on how the size changed.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
or remove content depending
on how the size changed.
A great example of this was
the child controller requesting
more size.
In this case, it's
not an indication
for that view controller
to actually lay itself out.
It's an indication that it needs
to actually add more content.
You also get this
call on rotation.
With rotation under iOS 8,
it's simply a bounds change.
So when you -- when
the device rotates,
your view controller will get
told that its size will change,
and you'll probably
see that the width
and the height have swapped.
And finally, you'll
also see these guys,
these messages called when the
resizable simulator changes
its size.
So when you're playing
around with the simulator,
you'll see that, as well.
Finally, is
containerViewWillLayoutSubviews
and viewWillLayoutSubviews,
and these are the
fine-grain controls
on UIPresentationController and
UIViewController, respectively.
It works just like UIView's
layout subviews, and it's meant
to do fine adjustments to the
subviews of your hierarchy.
And that includes child
content views, as well.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And that includes child
content views, as well.
So when your Presentation
Controller got that message
that the presentedViewController
needs to have a different size,
you would change that
presentedViewController's size
in
containerViewWillLayoutSubviews.
So now that we understand
how all the messaging flows
through the controller
hierarchy, let's take a look
at the demo that shows how we
do adaptivity to our demo app,
and then it also shows how
to use multiple Presentation
Controllers to show --
to display the same
view controller content.
>> So we're going to go back
to the same demo application
we were looking at earlier --
my photo management application.
Using the same API
that Jim talked
about for UI popover
Presentation Controller
adapting, we can adapt our
custom view controller too.
As you remember, we
have this side bar.
But when we transition to a
compact-width environment,
what we'd really like to have is
just a full-screen presentation.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
what we'd really like to have is
just a full-screen presentation.
Here, we'll change
the width to 320
and the size class to compact.
And check it out: we get a
full-screen presentation.
This is using that same
adaptive presentation style
at adaptivity API on
Presentation Controller
that we showed you in popover
Presentation Controller.
But what's really cool is
that we can still use our
custom animator object.
So you'll notice that when we
dismiss the view controller
by tapping the Save button,
we slide off from the right.
And when we present again,
we slide in from the right.
This is exactly what we want.
And to show that it
goes the other way,
I'll change the size class
back to regular, with the width
of 768 points, and boom:
it transitions perfectly
and gets placed correctly.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and gets placed correctly.
Next, I'd like to show
you something really cool.
Because Presentation
Controllers are not coupled
to their
presentedViewControllers,
we can switch out a Presentation
Controller that's used
for a view controller
with zero changes
to the presentedViewController.
I'm going to tap this
little switch in the corner,
which turns on Cool mode.
This flips some internal
state in my view controller
to use a different
transitioning delegate,
which will provide a
totally custom animator
and totally custom chrome
through its Presentation
Controller.
So when I tap a photo, instead
of that overlay side
bar presentation,
the view controller
slides in from the middle,
a beautiful leopard print
appears from the side,
and we get some totally
custom chrome.
You'll notice some things
about this custom presentation.
When we do the presentation,
while the unicorn
and the flower appear alongside
the view controller animating
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and the flower appear alongside
the view controller animating
in, the leopard print
animates by itself.
This is because
UIPresentationController can
animate its chrome in a
different animation block
than that which is used for the
view controller presentation.
So we can make that chrome
respond just how we want.
By the way, this sample
code, including Cool mode,
is available on the Worldwide
Developer's Conference website.
Just look for Look Inside.
Let's see how we implemented
this totally custom Presentation
Controller and switch the
Presentation Controller we used
for our overlay view controller.
Back in our root view
controller, I showed you setting
up our transitioning
delegate like this.
We're going to need to
augment this logic a little bit
to provide our other
Presentation Controller.
First, we'll check a
new internal method
that we've called
presentationShouldBeAwesome.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that we've called
presentationShouldBeAwesome.
And if this is true,
will use a totally new
transitioning delegate.
This transitioning delegate will
provide a custom animator object
to manage that scaling
animation,
and a custom Presentation
Controller
to manage the chrome
that you saw earlier.
Otherwise if that value
is not set to YES,
we'll just use the other
transition delegate
that you saw earlier.
And then, setting this on the
view controller will cause all
of that machinery to be put in
place when we go to present.
>> So to summarize what we
talked about here today,
there's only two points
that we really need
to take home with you.
First off, the
UIPresentationController,
UIKit ourselves are
eating our own dog food
and have really improved
our own API for alerts,
and for popovers,
and for search.
No longer do you need to put
their views into your hierarchy,
if they could be best
served by a presentation.
>> Additionally,
with Presentation Controller
representing the last piece
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with Presentation Controller
representing the last piece
in the puzzle for totally
custom presentations,
you can now build things
that you never could before
with custom chrome
and custom animations.
And we encourage you to go
make your own Cool mode.
We can't wait to see what types
of totally custom
presentations you're going
to add to your application.
>> So if you have more
information or questions,
Jake Behrens, the guy
in plaid down here,
is our App Frameworks
Evangelist.
He loves hearing from you guys.
Of course, there's
documentations
in the Apple Developer Forums.
More importantly, though,
there are related sessions.
This is the last talk
on UIViewController,
What's New in View
Controllers in iOS 8.
So all the sessions were
earlier in the week.
I highly recommend that you
check them out on the videos.
And that's it.
Enjoy the rest of
your conference,
and lets have a great
[inaudible], guys.
[ Applause ]