Transcript
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> Good morning, everyone.
[ Applause ]
I'm glad you guys could make it.
My name is Bruce Nilo.
I'm one of the engineers
on UIKit.
And we're going to be talking
about all the new stuff
that we've brought
into UIKit for iOS 8.
In case no one's told
you, it's a big release.
There's a lot of stuff.
And two weeks ago when I was
thinking about what I was going
to say, I said, "Piece of cake.
I'm just going to list
all the new features.
I'm going to also list all the
things that are going away.
And I'm done, right?"
Well, that's what
I ended up with,
and I realized I
really needed to cut
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and I realized I
really needed to cut
down on what I was
going to talk about.
So this is where we ended up.
And I just want to point out,
though, that there's a lot more
than what I'm going
to talk about.
One of the most important things
that we're introducing in iOS 8,
in case you haven't heard,
is we are providing APIs
that are more adaptive.
What this means is that your
user interfaces can more easily
respond to changes in size
and other changes, as well.
UISplitViewController used to be
a kind of a pretty simple class.
Well, it's grown up in iOS
8, and we're going to talk
about some of the new features
that UISplitViewController
has to offer.
We're going to, while we're at
it, show how it's really easy
to hide bars in ways
that you've probably seen
in some of our own apps.
Then we're going to
shift gears a little bit
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Then we're going to
shift gears a little bit
and talk about presentations.
Presentation controllers have
been introduced and are part
of a whole architectural
revamping
of how view controllers
are presented
and how you can create great
custom presentations yourselves.
That gave us the
opportunity, by the way,
to redo popovers, as well.
And popovers have
now become integrated
with UIViewController
presentations.
Finally we're going to talk-not
finally-we're also going to talk
about new a API that
we introduced
that builds upon
transition coordinators,
that also helps your
applications adapt.
And, finally, there's a subtle
but pretty important change
in terms of the coordinate
spaces
that you've grown to love.
And we'll talk about that
briefly when we wrap up.
So, you've probably
seen this picture,
or a variant of it, a few times.
Many hierarchical applications
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Many hierarchical applications
on a phone might structure
themselves this way,
inside of a navigation
controller.
And there might be some
detail that you would see
when you hit the Back button.
And on an iPad, you might choose
to structure it a
little bit differently.
Again, this is all
kind of familiar stuff.
But there's no particular
reason why you shouldn't be able
to do this on an iPhone, if
it suited your application.
We're going to show
how that's possible.
So prior to iOS 8, most of
your application coarse-grained
structure was determined by
looking at the device type,
and possibly the interface
orientation, as well as the size
in which your user
interface was being presented.
In iOS 8, we've taken
the first two
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In iOS 8, we've taken
the first two
and abstracted it a little bit
into two new concepts called
traits and trait collections.
Size is still available,
but typically size is a finer
grain type of layout operation
that can be easily
accommodated using technologies
like Auto Layout.
We're going to talk a little
bit more about the former.
We'll also address the
latter a little bit.
So what is a "trait collection"?
A trait collection, simply
put, is a set of traits.
Not too surprising.
On a phone, you might
see the window
of your application
return a trait collection
that has the following
traits: two size classes,
an idiom, and a display scale.
This typically is the way a
phone's traits are structured.
One of the most important traits
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
One of the most important traits
that we've introduced
is size class.
And size class deals
with, on a coarse level,
the available space that
your application has
and can therefore make decisions
about what its structure
should be.
Let's look at that quickly.
Here we have kind
of a cartoonish representation
of an iPhone.
And typically, the
vertical axis is going
to have a regular size class,
whereas the horizontal
axis is going
to have a compact size class.
If you rotate a phone,
we say that the size classes are
constrained in both the vertical
and the horizontal dimensions.
Now, an iPad is a
little bit more free.
It's regular in all
of its dimensions,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It's regular in all
of its dimensions,
or it has regular size classes
in all of its dimensions,
and that holds true when
you rotate it, as well.
But that's not the full story,
because some view controllers,
like split view controller, can
determine that its children,
in this case the primary child,
which is on the left side,
has a more constrained size
class in either dimension.
For a split view controller,
it constrains the
horizontal size class.
So, a size class is all about
informing your application
of the available space
in some coarse way
that you can make decisions
about how you would
substantially alter the
application's structure.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We have API on specific objects
that vend trait collections.
And in these cases they have
values for both the horizontal
and the vertical size classes.
Now, I like to think about the
trait collections that come back
from these objects as defining
a point in a trait space.
We've introduced a new
protocol that a number
of our objects conform to
which is a trait environment.
And you'll see the
hierarchy on the right is kind
of a window hierarchy
that starts from a screen
and proceeds down all the way
to the leaf view
elements that you have.
All these objects conform to
the trait environment protocol,
which means you can ask
them for a trait collection,
and what you get back is going
to be a point in a trait space
where every single
trait has a value.
And not all of these objects
define those values directly.
So, for example, if you asked
for the scale of a leaf,
the scale trait of the leaf
of a view, it might actually,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
the scale trait of the leaf
of a view, it might actually,
the system might
walk all the way
up to the screen to get that.
But the trait collection
that you get back will have
a value for that scale.
Finally, you will notice
that whenever a trait changes
in a trait collection,
your object,
the appropriate object will get
a traitCollectionDidChange just
before that object is laid out,
so you can respond to that.
So I kind of implied before that
you can, that a view controller,
such as a split view controller,
can override the
traits for a child.
How do you do this?
Well, we've introduced
a couple of new methods
on UIViewController which
allow you to do precisely this.
SetOverrideTraitCollection
can be used by a parent
to indicate what the
appropriate traits are
for any one of its children.
The trait collection that
you pass in, in this case,
isn't a point in a trait space;
it might just be a single trait
value which is then overridden.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
it might just be a single trait
value which is then overridden.
So what I wanted to do was,
before I go into the rest
of the talk, is I put together
kind of a toy application,
which is going to highlight
some of the features
that we're going to
talk about today.
This is kind of my canonical
little photo note-taking
toy application.
What you see here is basically
a pretty standard thing.
You see a navigation controller.
And I can hit the Back
button with this Photos,
and I get a list, which
is a simple table view.
I can select things.
That's great.
What's interesting, is that
this is actually a split
view controller.
Notice when I rotate, I stay
inside a navigation controller.
However, I can do
something interesting.
You see there's a Split button
on the bottom of this toolbar.
If I hit it, you can now see
a little bit more clearly
that this is, in fact, really
a split view controller.
You'll also notice that
when I-let's hide this.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You'll also notice that
when I-let's hide this.
I can tap and interact
with the bars.
I can create, I can move that
primary controller off-screen.
But one of the things we're
going to show is how easy it is
to hide the bars if I
tap on a view controller.
I can also get that Safari look
where the bars condense
really easily.
Alright. Let's go back
into a regular old
navigation controller look,
and let's hit this Note button.
The Note button is going
to do a presentation.
This is a view controller
presentation.
It takes advantage of
a couple of new classes
that I might mention as
we go through the talk.
What's interesting is this is,
in fact, a popover presentation.
Now, I'll get into
that a little bit later
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, I'll get into
that a little bit later
because it certainly
doesn't look
like a popover presentation.
But if I do something special
on this little toy app-well,
it didn't quite do it that time.
Now you'll see that that same
thing is, in fact, a popover.
And we'll go through
that a little bit.
Finally, I wanted to talk about,
a little bit about rotation.
And to do that, I'm going to
present another view controller.
This time it's a collection view
controller, which has a bunch
of little thumbnail photos.
And if I were to
rotate the device now,
the normal collection view flow
layout behavior would basically
relay things out so that
everything is oriented now
in the horizontal direction.
However, if I wanted to change
what happened when I rotated
so that it did something
more akin to this,
there's some interesting
things that we can do.
And this is a perfect example
of when you would use some
of the methods like willRotate,
interface orientation,
and so forth.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
interface orientation,
and so forth.
So we're going to talk about
that a little bit, as well.
Alright, so enough of a taste of
what we're going to talk about.
Let's go back to
the presentation.
And let's talk about
split view controller.
So as I kind of implied, split
view controller is now available
on the phone, as
well as on the iPad,
and it has this interesting
new property.
It has a property of being
collapsed or not collapsed.
Now, what does it mean for
a split view controller
to be collapsed or expanded?
Well, an expanded
split view controller,
it's kind of obvious,
might look like this.
However, it's not
just a question
of the two children
being visible.
So I'm highlighting the
secondary view controller
of this split view controller,
and you're going to notice
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of this split view controller,
and you're going to notice
that there's a little
button off to the left.
We call that the
displayModeButtonItem.
When I click on that,
I can expand
out the split view controller.
And even though we're
only looking
at the secondary controller,
that split view controller
is still expanded.
It is not collapsed.
And the reason why that is
is because it's possible
to show the primary
controller at the same time
as the secondary controller.
On the other hand, this is a
collapsed split view controller.
You'll notice that the
displayModeButtonItem that was
on the left side is gone.
You can no longer
show the primary
and secondary controllers
together.
They've been collapsed,
and you can now get
to the primary controller
by hitting the Back button,
which is up on the
top-left corner.
So that's kind of
what the difference is
between the split
view controller
in its collapsed state
and its expanded state.
It's important to know
that split view controller
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It's important to know
that split view controller
by default are collapsed
when they're
in horizontally compact
containers.
So by default on a phone, if
you use a split view controller,
it's going to appear in
this collapsed state.
So I've implied that you can
enable the expanded state
of a split view controller
on the phone already.
How do you do that?
Well, it's actually quite
simple and straightforward.
You probably know
the answer already.
First of all, you're going to
take your split view controller
and you're going to embed it
in a parent container view
controller, as follows.
You're then going to call
setOverrideTraitCollection.
And you're going to inform that
child split view controller
that it is now in a horizontally
regular environment.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The second you do that, the
split view controller morphs
into its expanded or
not collapsed state.
You'll notice that the
displayModeButtonItem,
which is titled Photos
in the lower left corner,
has now become enabled.
If I wanted to show both
controllers together,
side by side, I could click
on that displayModeButtonItem.
But we've also introduced
a property called
preferredDisplayMode, which
you can use programmatically.
If you set the
preferredDisplayMode
to the all visible
value, it's the same as,
the same behavior would
occur as if you clicked
on the displayModeButtonItem.
And you'll also notice the
displayModeButtonItem morphs
into this kind of
diagonal double arrow.
These items, this
display mode item
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
These items, this
display mode item
and this behavior
are all customizable.
And this is via delegate
API that you can look
at in the header files
that I'm not going
to have time to talk
about today.
So to go over some of that API,
preferredDisplayMode
is an enumeration.
Enumerated values are automatic,
hidden, visible, and overlay.
Automatic is the old behavior
that you are familiar
with on iPads.
Hidden and visible
are explicit means
by which you can
control the layout
of the split view
controller so that the primary
and secondary are side by side.
An overlay is an explicit way
that you can have the
primary kind of go
over the top of the secondary.
The displayModeButtonItem is
also accessible in this API,
so you can ask the split view
controller for it and put it
in whatever bar you want.
Although I'm not going to say it
explicitly, if you were to look
in the header files of
UISplitViewController,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in the header files of
UISplitViewController,
you would find that most
of the API that used
to be there is now deprecated
and replaced by new API.
One thing that I'd like
to say is that a lot
of people have always wanted
to control the split width,
and we've made that
really easy to do.
So there's a new
method, a new property,
preferredPrimary
ColumnWidthFraction.
And if I were to set
that to one-half, say,
the split width changes.
The API that enables
that is this.
You can set a minimum
and maximum bound
of the split width
in terms of points.
You specify the split
in terms of a fraction
and you can read back
the actual point value
with the primary
column width property.
So what have we learned here?
One is, is that split view
controllers can be used
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
One is, is that split view
controllers can be used
on both the iPhone and the iPad.
This makes it easy to write
code that is kind of agnostic
about the platform that it's
going to be deployed on.
If you have a certain
type of application layout
that makes sense in
either a collapsed state
or an expanded split view
controller state based
on the available space,
create a split view controller
and the split view controller
will adapt accordingly.
Split view controllers
are collapsed by default
in horizontally compact
environments.
The displayMode property
controls the appearance
of the primary or left
child view controller.
And you can also now
specify the split width.
So there are a lot of
other API that we added
to split view controller.
There's going to be a talk
immediately following this one
which talks about in more depth
all of the new adaptive APIs
that we've added
to UIViewController
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that we've added
to UIViewController
and UISplitViewController
that you can attend
and get more information.
So let's talk about
condensing bars.
It's all about available space
and highlighting your content.
So we wanted to make
it easy to do.
It's really easy now
to hide your bars.
Just set the hideBarsOnTop
property, and they're gone.
If you-
[ Applause ]
So what about that
gray, you know,
kind of Safari-looking
condensing bar behavior?
Well, we've added a
property for that, too.
Just set it to YES; when you
swipe, those bars condense.
[ Applause ]
So we've added a couple of
other properties, as well.
You know, the bars
can hide when you're
in a vertically compact
environment.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in a vertically compact
environment.
They might condense when
the keyboard appears.
You can control this
all programmatically
with an animatable property
called navigationBarCondensed.
Well, at least you can
control the condensing behavior
that way.
So, yeah, that's it
for condensing bars.
Okay, now the easy
stuff is all done.
Let's talk about
presentation controllers.
We have revamped the
presentation architecture
for view controllers on iOS 8.
You might recall that in
iOS 7 we allowed developers
for the first time to
customize what the presentation
transitions looked like.
Let's go back and
kind of talk about how
that looked and how
you did that.
So, first of all, what you
would do is, the view controller
that you wanted to present,
you would set the
presentation style to Custom.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you would set the
presentation style to Custom.
You would also set a
transitioning delegate
on that presented, on that view
controller to be presented.
And then you would just
present the way you normally do.
You'd tell the presenting
view controller
presentViewController, at which
point the system takes over.
UIKit will ask the
transitioning delegate
for the animation
controller that is your object
that is vended
by the transitioning
delegate that you've set.
At which point UIKit
prepares this internal object
which conforms to this context
transitioning protocol to set
up some information that
you need to know in order
to drive your custom transition.
The views that are participating
in this custom presentation
are accessed via this
viewControllerForKey property.
And then there's
frame information
and all of that stuff.
Now this object is passed into
another method that is generated
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now this object is passed into
another method that is generated
by UIKit to your animation
controller, animateTransition.
You do your animation, the
presentation's complete,
and the animation
controller goes away,
and everything's good.
Well, there were a couple
of problems with that.
Let's look at the view hierarchy
to see what those
problems might have been.
So we have the presenting
view controller's view.
When the animation controller's
vended, we set up kind
of the environment in which this
transition animation is going
to take place.
That's kind of the container
view that the context,
the transitioning
context is pointing
to that your animation
controller accesses.
When we send the
animateTransition message
to the animation controller,
it's the animation
controller now that's groveling
in the view hierarchy,
adding special views,
adding the presented
view controller's view,
and one of the neat things-it
was a feature in iOS 7-is
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and one of the neat things-it
was a feature in iOS 7-is
that we didn't remove
the presenting view
controller's view.
And so this is what
it ended up with,
and the animation
controller went away.
Okay, so the first question
that comes to mind is,
what object owns all these
other-these views that are lying
around that just got added
by that animation controller?
Well, there wasn't a
good answer for that.
In fact, that ended up
causing a tight coupling
between the animation
controllers
that were doing a presentation
and the animation controllers
that were doing a dismissal.
Sometimes that was
easy to manage.
Sometimes it caused problems.
It often caused problems
when view controller
presentations were being stacked
on top of one another.
So let's look at
what we do in iOS 8.
It's going to look pretty
similar in the beginning.
You're going to set
the presentation style,
just like before.
You're going to set a
transitioning delegate,
just like before.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You're going to send a
presentViewController message
to the presenting view
controller, just like before.
However, now the transitioning
delegate has grown a couple
of new methods.
You can now get then
this new object called a
presentation controller.
And now it is the presentation
controller that's responsible
for asking the transitioning
delegate
for the animation
controller and, in fact,
for driving the actual
transition.
Now, there's a lot of
neat things under the hood
that are going on
here, and there's going
to be a whole talk
tomorrow, I believe,
about presentation
controllers, in depth,
and how we used the UIKit to
introduce some new API, as well.
But for now, let's
look at what's going
on in the view hierarchy.
So now, you'll remember you
have this view hierarchy
that corresponds to
this custom transition.
The presentation
controller's still around,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The presentation
controller's still around,
and it holds a reference
to the container view,
which is where the whole
transition is happening.
It also holds a reference
to this thing called
a presented view.
Now I want to point out,
the presented view is
not necessarily the view
of the view controller
that's being presented.
Maybe I put a drop
shadow around that view
because that's what my
custom presentation demanded.
In order to accommodate that,
we had to augment the context
transitioning protocol a
little bit.
So we added this new
method called viewForKey.
ViewControllerForKey
still exists,
but viewForKey may
return a different view
than the viewControllerForKey.
And so when you build a
custom animation controller,
you want to make sure that
you use the viewForKey methods
to figure out which views
are actually participating
in the animation.
A presentation controller can
also add other types of views
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
A presentation controller can
also add other types of views
that are completely
unknown to other types
of presentation controllers,
say, like a dimming view
that it wants to put over the
entire back of the presentation.
I mentioned that in iOS 7,
by default the presenting view
controller's view was left
in the window hierarchy.
Well, presentation controllers
have a very rich API,
and if you build your own,
you can specify properties
such as shouldRemove, should the
presentation view controller's
view be removed or not.
And if you set it to YES, it
will automatically get removed.
There's one other property
which is, I'm raising here
because I think anyone
who builds a custom
presentation controller needs
to at least be aware of,
which is the
shouldPresentInFullscreen
property.
What this means is that a
presentation will effectively,
its container will be in the
window and its, and the frame
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
its container will be in the
window and its, and the frame
of that container view will
effectively be the bounds
of the window.
If you implement a custom
presentation controller and set
that property to NO,
your presentation
will no longer adapt.
Now, I know that doesn't make
quite a lot of sense yet,
but we're going to
go through some stuff
and then it will
become more clear.
So let's quickly talk about some
of the API that has been added
for presentation controllers.
One is that you'll
notice that it appears,
it conforms to the
appearance container protocol,
the trait environment
protocol, and this new protocol
which we'll talk about in a
bit called content container.
We talked about the
containerView properties
and the presentedView method
and these two other properties.
As I said, there's a whole bunch
of methods and logic available
for you to create fantastic
new custom presentations.
But that's beyond the
scope of this talk.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But that's beyond the
scope of this talk.
So armed with this
new architecture,
let's talk about some
features that we've added.
First of all, all the old
iPad-only presentations are now
available on the iPhone.
By default they're
going to present
to full-screen presentations.
But there's some power
under the hood here.
So new presentation styles that
are available that we've added,
again, that are both available
on the phone and the iPad,
is an OverFullscreen
presentation,
an OverCurrentContext
presentation, and,
I think I mentioned before,
popovers are now
presentations, as well.
Every presentation has an
associated presentation
controller, and you can access
these with these methods.
And the reason you do so
is because you often want
to set the delegate on the
presentation controller.
And now the plot thickens
because the delegate is,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And now the plot thickens
because the delegate is,
in fact, the object
that is going
to help your presentations adapt
to different trait environments.
Before we get into that,
let's make sure we all
understand what the new
presentation styles
are all about.
OverFullscreen is kind of
a full-screen presentation
that doesn't remove
the presenting view
controller's view.
So you can create interesting
kind of overlay types
of presentations
really easily now.
OverCurrentContext
is pretty similar.
If you know what current
context presentations are,
it's presentations that are
kind of constrained inside
of the presenting view
controller's super view.
So that's what
OverCurrentContext gives you.
And, finally, we have popover.
And we all know what
popover looks like.
This is a good opportunity
for me to say that we're kind
of soft-deprecating
UIPopoverController.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of soft-deprecating
UIPopoverController.
We're not hard-deprecating
it, but you should be aware
that all the popover controller,
old popover controller API
is now being shimmed kind
of behind the scenes into
a popover presentation.
This might create a couple
of differences in behavior.
For the most part, these things
are functionally equivalent.
There are a few corner cases,
though, that you might run into.
For example, if you have
a pop, if you have code
that was presenting a popover
and then immediately
dismissed it
and did another presentation
the next line, you're going
to have to defer that.
And you can do that
pretty easily
by grabbing a transition
coordinator
and scheduling the
new presentation
for after the dismissal
of the popover.
So let's talk about how
presentations can adapt
to changing trait environments.
As I mentioned, all of
these presentations, styles,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
As I mentioned, all of
these presentations, styles,
adapt by default in horizontally
compact environments
to full-screen.
Now, it's possible to
change that default behavior
to be OverFullscreen or
to be not, which means,
"Please don't adapt; keep
my presentation controller
as is, in charge."
The way you control this
behavior, as I implied,
was you set the delegate
and you're going
to override a couple, or you're
going to implement a couple
of methods on that delegate.
So here they are.
The first is
adaptivePresentationStyle
ForPresentationController.
It does what its name implies.
It's called when the
presentation moves
into a horizontally compact
environment and you return one
of those presentation styles
that I enumerated earlier.
There's another method that
might be a little less clear
which allows you to actually
return a whole new view
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
which allows you to actually
return a whole new view
controller that should be
presented in that style.
And we'll see what
that means in a bit.
There's a PopoverPresentation
ControllerDelegate,
which I'm not going to
go into detail about.
But suffice it to say
that that delegate,
in addition to providing the
adaptive APIs, also exposes all
of the properties and
methods that you need
to get the functionally
equivalent popover behavior
you're used to.
We'll see a little bit of a
code example of that shortly.
In fact, very shortly.
So what does it mean to
present a popover in iOS 8?
Well, you could use the
old APIs, as I said,
on UIPopoverController.
But I want to show how you
would do it using the new APIs.
So the first thing you
do, not too surprisingly,
is you set the presentation
style to popover.
Now, interestingly
you can grab the
PopoverPresentationController
before you've even
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
PopoverPresentationController
before you've even
presented anything.
That's important because you're
going to need to do things
like say, "What's the bar button
item that I'm pointing to?"
and "What do my arrows
look like?"
You might also want to specify
a preferred content size
so that we know kind of
how to size the popover.
And, finally, you
present the popover.
So what's that going
to look like?
So if I wrote that code and
executed it just the way you saw
on the previous slide, it's
going to look like that.
Now, the first thing I want
to say is it is a
popover presentation.
The second thing I want to say
is there's a couple of problems.
So the first problem is that
it underlaps the status bar.
This is one of my favorite bugs.
I can't tell you how
many bugs I get about
"My content's underneath
the status bar."
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
"My content's underneath
the status bar."
I'm not going to go into that,
but I thought I would
just mention that.
The second thing is
it looks pretty bad.
And a more subtle point that
I'm sure all of you got was,
it's a popover presentation
and I can't tap anywhere
to dismiss it.
Okay, so what are
we going to do?
Well, we're going
to go to our friend,
the trusty presentation
controller delegate,
and we're going to use some
of those new adaptive APIs.
And in particular, I'm
going to implement,
I would implement
adaptivePresentationStyle
ForPresentationController.
This time I'm going to have
it return OverFullscreen.
I'm going to use this brand new
view object that we introduced
in iOS 8 called the
UIVisualEffectView,
which will become your best
blurry friend in iOS 8.
And then inside of
that implementation,
I can adjust the content, like
where it's actually positioned.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I can adjust the content, like
where it's actually positioned.
So that should address a
couple of the problems.
So now I get this kind
of nifty blurred view,
which looks a lot better
than that ugly white thing.
I've repositioned my content.
It's a different adaptation.
The reason it's blurring
so nicely is
because I didn't remove the
presenting view controller's
view underneath.
However, we still have the
problem that there's no way
to dismiss the popover.
So how do we fix this?
Well, you might have recalled
that there was another
delegate API that I talked
about that I deferred kind
of explaining why I,
why it was useful.
We're going to go
back to the delegate,
and this time we're going
to also implement
presentationController:
viewController
ForAdaptivePresentationStyle.
So this is pretty nifty.
What we're going to
do is we're going
to create a navigation
controller whose root view
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to create a navigation
controller whose root view
controller is the currently
presented view controller.
We're going to add
a Dismiss button
to that navigation controller's
bar, navigation bar.
And then we're going
to be good to go.
So now when I hit Note,
I get this great looking
OverFullscreen adapted
popover presentation.
There's a Done button,
so I can dismiss it.
So that's great.
But what if I actually
just wanted a popover?
Well, you can do that, too.
Let's go back to our
trusty delegate friend,
and it's this time an
adaptivePresentationStyle
ForPresentationController.
All I need to do is return None.
And if I return None,
the presentation controller is
not going to be adapted at all.
And now when I hit the Note
button, I get an actual popover.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And now when I hit the Note
button, I get an actual popover.
[ Applause ]
So let's kind of go
over what we saw here.
First is, presentation
controllers are a new object
in iOS 8 that make it
easier and more consistent
to create powerful
custom presentations.
They are an improvement over
what was introduced in iOS 7.
Every presentation is associated
with a presentation controller,
which can be accessed,
and you can use
that presentation controller
to do various things,
depending on the
presentation control.
But all presentation controllers
can use, can have a delegate
that conforms to these
adapting delegate protocols.
One thing that isn't
on this screen is
that popovers are also
presentation controllers,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that popovers are also
presentation controllers,
or are presentations
that have an associated
presentation control.
And, finally, if you create your
own presentation controller-I
mentioned this earlier-if
it returns YES
to shouldPresentInFullscreen,
it will be able to adapt.
If, on the other hand, your
presentation controller is kind
of a current context
style presentation,
it doesn't really make
too much sense for that
to adapt, so it doesn't.
We're not going to go through
those adaptive delegate calls
in that case.
Alright, that's enough for
presentation controllers,
although this topic
actually kind of overlaps
or has some overlap with
presentation controllers:
transition coordinators.
Again, those were
introduced in iOS 7.
What is it?
Well, it's an object that
conforms to this protocol.
Every transition coordinator
has an associated transition,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Every transition coordinator
has an associated transition,
and that associated transition
is oftentimes deferred.
And this transition
coordinator is kind
of holding this freeze-dried
transition as it gets passed
around to various pieces of code
that can then use this method
called animateAlongside
TransitionCompletion.
So you can kind of queue
up blocks of animations
that are going to
execute in that kind
of deferred transition
animation that is associated
with that transition
coordinator.
So that's pretty powerful.
It was introduced in iOS 7,
and we're taking advantage
of this object in
a few new APIs.
So, two of these are
viewWillTransitionToSize:
withTransitionCoordinator;
next one is
willTransitionToTraitCollection:
withTransitionCoordinator.
Now, I'm not going
to talk too much
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, I'm not going
to talk too much
about
willTransitionToTraitCollection.
But I did mention earlier that
trait collections are kind
of associated with coarse
application structure.
And one of the best ways
to adapt an application-it's not
the only way, but it's one-is
to implement
willTransitionToTraitCollection,
and when a trait collection,
such as a size class, say,
that may change, say,
if you rotate a device
or if you set an
override trait collection,
this method will be invoked
and you can actually do some
coarse-grained application kind
of re-jiggering, if you want.
Now, again, there's going
to be a whole talk that goes
into a lot more detail on
that particular method.
It's very parallel
to the other method,
viewWillTransitionToSize:
withTransitionCoordinator
that I'm going to talk about.
By the way, did I forget
to mention this is part
of a new protocol called the
content, UIContentContainer?
I mentioned
that UIPresentationController
conforms to this.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that UIPresentationController
conforms to this.
UIViewController also
conforms to this protocol.
These objects support a notion
of a preferred content
size that you can set.
And that's kind of the
request, if you will,
that you like your content size
to grow or shrink depending
on the circumstances
of your application.
When you set that, your
parent container object,
whatever that might be-it might
be a parent view controller,
it might be a presentation
controller-will get a
preferredContentSizeDid
ChangeForChildContentContainer.
In that method, the
parent can decide what
to do with the request.
If it decides that it actually
wants to honor the request,
it may turn around and call
viewWillTransitionToSize:
withTransitionCoordinator
on the child,
which gives the child
the ability
to animate alongside
that size change.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to animate alongside
that size change.
So let me kind of make a
small digression and kind
of give a bit of wisdom.
And I realize that Anonymous
is actually Josh Shaffer
because I think I
heard this from him.
And you might wonder, why am I
throwing this random point out?
First, let's see
what we mean here.
Basically if I rotate
a device in general,
that's all that's happening.
The fact that there's an
animated transform rotation is
kind of beside the point.
And most of the time your
application really doesn't need
to do anything.
It's going to gracefully
stretch and do whatever it needs
to do as the bounds change.
Okay, so what does that mean?
Well, you will recall that we
have these APIs that have been
around for a long time.
Well, we're getting rid of them.
And [Applause]-ah, I thought
you guys all loved these.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And [Applause]-ah, I thought
you guys all loved these.
So one of the things about these
APIs, and I think I've been
on this stage before saying,
"You shouldn't do layout based
on interface orientation.
You shouldn't use these
methods to drive your layout."
They're really kind
of focused methods.
You wanted to use them because
you wanted to participate
in this rotation event.
So now we've generalized it.
We have this other method called
viewWillTransitionToSize:w
ithTransitionCoordinator
that takes over.
So, first of all, all those
rotation callbacks can be
replaced with this
more general notion
of viewWillTransitionToSize:
withTransitionCoordinator.
I talked about setting
the preferred content size
and that you get
this notification.
Well, so if your widget
in the notification center
actually wants to request
to be displayed in a slightly
larger space or smaller space,
this API will be called on your
widget so that you can, in fact,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
this API will be called on your
widget so that you can, in fact,
animate alongside or run
some code that executes
after the resizing
has taken place.
I said that you can, your
own apps can respond to this.
Now, at one point I was going
to have a whole bunch of slides
that showed you how to implement
your own transition coordinator.
I didn't have time to do that,
but it's relatively
straightforward
and you can implement your own
transition coordinator that's
implement, that's
kind of associated
with your own transition
animation.
And if a child changes its size,
you can call
viewWillTransitionToSize
and pass in that object using
the transition coordinator.
Okay. So to really be
a replacement for kind
of the rotation, we kind of
had to give a little bit,
kind of get down off of our
high horses of, you know,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
kind of get down off of our
high horses of, you know,
the way things should be and
acknowledge the way things are.
And we added this
target transform.
So it's not so much
the orientation
that you really care about.
It's like what's the
transform that's kind of being,
that I'm participating
in an animation with?
The reason this is
important, and I'm going to get
to this later, is
we've actually changed
where the rotation
transforms live.
Some of you guys
may have noticed
that whenever you do a rotation
that it's the root
view controller
or the full-screen view
controller's layer that has kind
of the affine rotation
transformation directly
associated with it.
That's no longer
the case on iOS 8.
So when you implement
viewWillTransitionToSize,
you can ask for the
target transform,
and if it's not identity,
you are inside
of a rotation resize event
that you can do some
interesting things with.
So to show how these are similar
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So to show how these are similar
or how this is a
direct replacement
for the old rotation callbacks,
this is some, you know,
skeleton code
where viewWillTransitionToSize
first calls myWillRotateTo
InterfaceOrientation,
which is exactly when it,
the old call would
have been made.
And then it uses the
transition coordinator
to animate alongside
myWillAnimateTo
InterfaceOrientation call.
And, finally, in the
completion block is
when you would call
myDidAnimateFrom
InterfaceOrientation.
So you can kind of see
that WillTransitionToSize:
withTransitionCoordinator
is identical
or provides the identical
functionality.
It's actually more powerful
and, from my perspective,
it's a lot easier to
read code like this.
Okay, I know you
guys are all sad
that these methods have gone.
So if you don't implement
viewWillTransitionToSize:
withTransitionCoordinator
will still call them,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
withTransitionCoordinator
will still call them,
just don't implement it.
A subtle point that
you should be aware
of is most view controller
transitions are immediate
when the system calls
this method.
What does that mean?
It means that if you needed
to rearrange your
application's structure
in some significant way and
you do like pushViewController
or something like that, the
entire view hierarchy is going
to be updated immediately.
So you can do neat
things with that
in your transition animations.
Unlike rotation callbacks,
by default we're going
to forward
viewWillTransitionToSize
through the entire
presentation hierarchy,
through the entire
view controller
containment hierarchy.
All you need to do is call
super to get that behavior.
If you don't, we will no
longer propagate those.
So you probably want
to call super.
Finally I'm going to say that
you only really need this,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Finally I'm going to say that
you only really need this,
I kind of implied it before,
when you're doing some kind
of special size transition.
More often than not, autolayout
and other techniques are going
to be-layout techniques are
going to more than suffice
to handle a size transition.
So I wanted to, I showed this
example earlier in the demo
and I wanted to show
when would be a good time
that you might want to use
viewWillTransitionToSize.
So here's a collection
view controller.
If I rotate it, what's
going to end up happening
if I did nothing at all,
is I get-the default collection
view flow layout will give me
something like this.
You'll notice kind of how the
thumbnails have shifted around
and things have resized and
maybe that's what I want.
But maybe I want something else.
Maybe I don't want the
collection view controller's
view to rotate at all,
and I want to apply the counter
transform on each of the cells.
Something like that.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Something like that.
So this would be a great time
to use viewWillTransitionToSize.
And let's see how
that would look.
The first thing that you do is
you get that targetTransform
that I was talking about.
And we're going to
invert it, and we're going
to grab our old view
bounds and set things
up for our transition
coordinator.
So inside the alongside block,
we're going to basically
call transition
coordinator animateAlongside.
We're going to update
the transform
to basically undo the rotation
transform that's taking effect.
You'll notice that
I'm composing it
with the existing
transform because, hell,
I might be in a different
orientation already.
So I do that.
I then squirrel away
the counter rotation,
which effectively is
the transform that is,
I am animating with right now.
I update my bounds
to the old bounds
because I've now applied
the counter transform
on the collection view
controller view's transform.
I'm done. I'm going
to not rotate,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm done. I'm going
to not rotate,
the collection view controller
isn't going to rotate,
and those cells aren't
going to rotate either
until I hit the completion
block, at which point I'm going
to apply the counter
rotation to each of them.
Okay, so what did we learn?
Transition coordinators
are being used
in a lot of our adaptive APIs.
You can use a transition
coordinator in response
to preferredContent
SizeDidChange calls.
All of the rotation callbacks
are being deprecated.
That's about it.
So let's talk about
screen coordinates.
And this gets to where the
transforms are being applied
when we rotate.
So in iOS 8-I mean, iOS 7,
the screen orientation
was always fixed to kind
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
the screen orientation
was always fixed to kind
of the top left position
in portrait.
This gave you a fixed,
unchanging coordinate
system, if you needed it.
We ended up communicating
things like keyboard size
and other things in terms of
this fixed coordinate system,
even though the actual interface
orientation was the current top
left corner.
So in iOS 8, we're
changing that a bit,
and everything is now
interface oriented.
So the keyboard size
notifications are going
to be interface oriented.
A few other things are going
to be interface oriented.
But you still may need a
fixed coordinate system.
How do you do that?
Well, we introduced
a new protocol
called UICoordinateSpace.
And, by the way, this
is not in seed one.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And, by the way, this
is not in seed one.
This will come out in a, you
know, a soon-to-follow seed.
We introduced a protocol
called UICoordinateSpace,
a couple of conversion routines,
to and from these
coordinate spaces.
It also implements
the bounds call.
UIView conforms to
this directly,
which isn't too surprising.
All the existing
conversion routines,
by the way, stay in place.
UIScreen now has grown
a couple of properties
that vend two different
coordinate spaces.
One is the default interface
oriented coordinate space
and the other is the old
portrait fixed coordinate space.
So if I wanted to
convert to and from
that fixed coordinate space,
what you effectively
do is you grab
that fixed coordinate space
off of the window's screen
and you can convert
to and from views.
So let's go over briefly
what we discussed today.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We talked a little bit
about trait collections,
how they affect kind
of the gross coarse-level
application structure
of your application, how
you can override them,
how view controllers can
override them, and a little bit
about how your view controllers
and your application can
adapt to those changes.
We introduced some of the new
UISplitViewController features,
and there are a lot of them.
I encourage you to kind of
look at the header files
and attend the talk after
this to see all the new
and amazing things you can do
with split view controller.
There are some new
simple properties
on navigation controller
that will allow you
to condense and hide bars.
We've introduced
PresentationController and,
in particular, we've revamped
the presentation hierarchy.
Popovers are now presentations.
We've introduced some
new presentation styles.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We've added some new
API for transition
that utilize transition
coordinators,
and these are becoming
interesting objects
that are becoming more present
in more and more of our APIs.
We've deprecated the
old rotation callbacks
or the existing rotation
callbacks,
can be replaced by-that
logic can be replaced
by this new method,
viewWillTransitionToSize.
And, finally, screen bounds
is now interface oriented.
There's a lot of things in
UIKit that are new for iOS 8.
This is just some of them.
I encourage you: the talk right
after this one is
Building Adaptive Apps
with UIKit that's going to
go into much more detail
about all these new and great
adaptive APIs we have in UIKit.
Tomorrow there's going to be
a talk that goes into depth
about presentation controllers,
how we internally use them
to implement new replacements
for search controller
and alert controller.
We are, there was a talk
yesterday, I believe,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We are, there was a talk
yesterday, I believe,
about creating extensions
that leverage the
viewWillTransition ToSize APIs.
There are some nice talks on
Friday, or there is a nice talk
on Friday about how
you can make your,
basically your transition
animations,
more responsive to
user interaction.
For more information,
please contact our
evangelist, Jake Behrens.
He'll be more than happy
to get you the sample app
and answer your questions and
tell you how it all works.
And have a great rest
of the conference.
Thank you.
[ Applause ]