WWDC2015 Session 205

Transcript

X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[Applause]
>> Peter Hajas: I am so excited
to be here today to talk to you
about multitasking on iPad.
My name is Peter Hajas, I'm
a UIKit Frameworks Engineer,
and later on I'll be
joined by my colleagues,
Jacob Xiao and Kurt Revis.
So you can see that even UIKit
is multitasking for this talk.
Multitasking is a giant feature,
and so we have split
it among three talks,
of which this is the first.
Tomorrow afternoon
you can hear all
about the great new
media enhancements
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
about the great new
media enhancements
that we have brought
to iPad and iOS 9,
and learn about
picture-in-picture video
and how your app can use the
camera alongside other apps
in multitasking.
Later that same day
is a really great talk
about how your app can be a
great citizen alongside other
apps that are multitasking
on iPad.
I really encourage
you to check out both
of these talks tomorrow.
Today we're going to
go over three topics.
The first, multitasking
in your app: what is it,
why should you adopt it,
how you can adopt it,
and what does it mean
at the UIKit level?
The second is changes
that we have made to UIKit
to make your multitasking
adoption experience really easy.
And the third is making
the most of the latest
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And the third is making
the most of the latest
and greatest UIKit APIs to make
sure your app really shines
in multitasking.
Let's get started.
As you saw in the keynote,
multitasking brings a great new
experience to users on iPad.
They can be doing one of
their favorite things,
like browsing the web, and
slide in from the right
to interact with another app.
We call this mode 'slide over.'
The user can then tap the
divider to the left of the slide
over tap to pin the
apps side by side.
As you saw on the keynote, we
call this mode 'split view.'
Being that you're all
iOS developers I'm sure
that you're really familiar with
our UISplitview Controller API.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that you're really familiar with
our UISplitview Controller API.
And I can assure you that
that's completely different
from split view.
[Laughter]
>> Peter Hajas: The user
can grab the divider
between the two applications
and resize them
for a 50/50 split view UI.
They can then take the divider
and keep dragging to the left
to promote the side app, in this
case, Maps, to be full screen.
Then they may choose to
slide in another app,
or the same one,
again from the side.
With multitasking on iPad in
iOS 9 the user is in control
of the experience, the apps
that are running, and the sizes
that those apps are running at.
There is another really cool
feature of multitasking in iOS 9
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
on iPad, and that's
picture-in-picture video,
which you can hear all
about at tomorrow's media
multitasking talk.
Today we'll be covering how your
applications can adopt split
view and slide over.
In order to understand how to
adopt those, it is important
that we talk about something
that's become increasingly
important in UIKit apps
and that's adaptivity.
In the past, we have
encouraged you
to make your applications
universal.
This means the same app can run
on the iPhone and on the iPad.
Last year we introduced
a simplified way for you
to do the check for what type
of interface you should
be providing to your user,
through the introduction of
the horizontal size class.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
through the introduction of
the horizontal size class.
Last year, iPhones in portrait
have the compact horizontal
size class.
They traditionally display,
for example, a single column
of content, whereas iPads
have the regular horizontal
size class.
Many of Apple's own system
apps use this to indicate
that they should show
multiple columns of content
and change the information
architecture
that they present to the user.
Also with the devices at last
year's Worldwide Developer
Conference, this held true
while the devices were held
in landscape, compact
horizontal for the iPhone,
and regular horizontal
for the iPad.
So that was last year's
Worldwide Developer Conference.
But if you look closely,
there was another message last
year that's really obvious
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
there was another message last
year that's really obvious
if you use a microscope;
we were telling you
to get ready for the iPhone 6+.
Like our existing iPhones,
the iPhone 6+ has a compact
horizontal size class.
But when rotated into landscape,
it has the regular
horizontal size class.
This is the first time that
an app can have different size
classes while it's running.
And that brings us to this year.
Similarly, if you take
this year's invitation
and draw the lines and rotate it
where you know it logically
makes sense, it forms a P,
the P of iPad multitasking;
it is obvious.
[Laughter]
>> Thank you.
So how does iPad multitasking
work with adaptivity?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So how does iPad multitasking
work with adaptivity?
Let's take an example
of a slide over app.
The user slides over from
the right side of the display
and the app comes up in a
compact horizontal size class.
It shows what we would
traditionally refer
to as the iPhone experience.
Then the user may choose
to resize their app
to be full screen and
then it will change
into the regular
horizontal size class
and display its traditional
iPad UI.
Two new things happened here
that never have been
possible before on iPad.
First, the app began its life as
a compact horizontal size class,
something that has never
been possible on iPad before.
Second, the app changed
size classes
when the user resized it.
This is also brand new to iOS 9.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So what does this mean for
your app and your users?
Let's look at it from
those users' perspectives.
They could be browsing the
web and want to interact
with another one of their
favorite apps on iPad.
So they'll slide in from
the right and they'll want
to see your app in this list.
By adopting multitasking in
your app on iPad and iOS 9,
you will let users get into
your app more, spend more time
in your app while they use it
alongside their other favorite
apps on iPad, and use
your app in brand-new ways
that you may have never
imagined in concert
with their other apps.
Users will expect that all apps
on their iPad support
multitasking,
and we're here to
help you adopt it.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and we're here to
help you adopt it.
Let's go through
just how easy it is
to add multitasking
to your iOS app.
I have got great news for
you: it is really easy.
All you have to do is
use the Xcode 7 beta
and create a new project.
All new projects created
in Xcode 7 have iPad
multitasking enabled by default,
and all the code you
write will be running
in multitasking, and that's it.
Just make a new project.
[Laughter]
>> Peter Hajas: Now, right
before this talk, off stage,
some of my colleagues
reminded me that there are one
or two existing apps that may
choose to adopt multitasking.
And for those apps,
it is easy also.
You just need to follow
three simple steps.
First, build your app
with the iOS 9 SDK.
You can do so in the build
settings of your Xcode project.
Second, support all orientations
in the iPad version of your app.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Second, support all orientations
in the iPad version of your app.
At last year's conference,
we encouraged you to think
of orientation changes as
simple bounds size changes.
And this advice continues
with iOS 9,
because a multitasking resize is
just that, a bounds size change.
But because the user
is in control
of what orientation they're
holding their iPad in,
in multitasking it is important
that your iPad app
supports all orientations.
Finally, the third
thing you'll need
to do is use Launch Storyboards.
Introduced last year, Launch
Storyboards are a great way
for you to specify
one storyboard
as the launch appearance
for your app in all sizes,
configurations, orientations,
and devices that iOS supports.
With all the different sizes
supported by iPad multitasking,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
With all the different sizes
supported by iPad multitasking,
using Launch Storyboards is
a requirement for adding it.
One important note here --
if your app requires a
full-screen experience,
you can opt out by using the
UI Requires Fullscreen key
in your info.plist.
Now that we've gone
over just how easy it is
to create a new project
with multitasking or add it
to your existing project,
let's go through how it works
in your app at the UIKit level.
There are some very
important changes
that you should be aware of.
In the past, UIScreen Bounds
has returned the visible bounds
of the entire display
of the device.
And this continues in iOS 9.
Whether your app is running
in full screen or is resized
for multitasking, one
really important change is
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
for multitasking, one
really important change is
that UI Window Bounds, well, it
returns your window's bounds.
But your window's bounds will
no longer always be the same
as the screen bounds of
the device, for example,
when your app is
resized in multitasking.
Another important change is
that your window's frame origin
is always in the top left,
(0,0), whether you're
running on the left side
of the screen or
on the right side.
We don't want you to have
to worry about which side
of the screen you're on or what
other apps you might be running
next to.
We only want you to focus on
the experience in your app.
Now let's talk about the
different types of transitions
that can take place when
your app is being resized.
We'll use an example, an app
that's great with multitasking
in iOS 9, the brand-new
Notes app.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in iOS 9, the brand-new
Notes app.
This is the new Notes
app running
as a slide over app on iPad.
You will notice that
it looks a lot
like the Notes app on iPhone.
It shows a single column of UI.
We call this the
horizontally compact size class.
Later on, the user
may resize our app
and at a certain point
we'll change what class
of experience we should
be providing to the user.
Notice that Notes now displays
two columns of content.
This is that same
horizontally regular size class
that we saw earlier.
Notice how Notes has changed
the information architecture
of the app to show your
notes list on the left
and a note on the right.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This is the type of change
that you should use size class
transitions to influence.
One important thing to note
about these transitions is
that not all resizes will
trigger a size class change.
For example, if Notes is
running in split view on iPad
and the user resizes
the app a little bit,
it won't change size classes.
It still shows a
single column of UI.
Instead of changing
the experience class,
Notes uses this new size
to influence its view's
positioning and layout.
Look again as we make the
app a little bit smaller.
Still a single column of UI.
UIKit has made some important
changes to our current API
to make this really easy
for your app to adopt.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to make this really easy
for your app to adopt.
One of these technologies
that we encourage you
to use is Auto Layout, UIKit
and AppKit's declarative
view layout system.
Auto Layout allows you
to position your views
using constraints,
and then when bounds changes,
Auto Layout will
reset their centers
and frames appropriately.
It is really easy to use.
New in iOS 9, we have added some
great new constraint convenience
API that makes it really easy to
create Auto Layout constraints.
Also if you use the leading
and trailing layout attributes,
you'll get a lot
of the right-to-left language
support for free in your app.
Another area of importance
that we saw
for helping apps handle resizing
is in the form of legibility.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
for helping apps handle resizing
is in the form of legibility.
We're introducing a
new API on UIView,
'readable content guide.'
This will return
a UI layout guide,
which represents the
legible region in a UIView.
This means that if you use
this readable content guide
to position your views,
they will always be
at a legible width.
For example, in this sample app,
which uses readable content
guide, the view is full size,
it is the size of
the whole iPad.
But the readable content guide
has given it some generous
margins to make sure that the
lines are really easy to read.
A great feature of using
readable content guide is it
will automatically adjust
depending on what size
and device the app
is running on.
It also works great
with dynamic type,
something that we
encourage all apps to adopt.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
something that we
encourage all apps to adopt.
You can also use it with
or without Auto Layout.
A common component in many
iOS apps is UI Table View.
And we wanted to make legibility
really easy there too.
So we have introduced a new
property on UITableView,
'cell layout margins
follow readable width.'
When this property
is set to yes,
your table view's cells' content
view will have layout margins
set such that content laid out
relative to those margins is
at a comfortable, legible
width for the user.
This means that by simply
using the layout margins
in your UITableView cells'
content view, the contents
in your cells will be
at a comfortable width whether
running in full screen on iPad
or in a smaller screen such
as an iPhone in portrait.
Now that we have talked about
some of the great improvements
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now that we have talked about
some of the great improvements
for multitasking, I would like
to hand it off to my friend
and colleague, Jacob
Xiao, who is going to talk
about what's changed in
UIKit and some best practices
for your apps to follow.
Jacob?
[Applause]
>> Jacob Xiao: Thanks, Peter.
I would like to tell you
some of the changes to iOS
to support multitasking,
and also some best practices
for working with those
changes in your apps.
So, last year, we asked to
you make your apps adaptive
by using traits and
size classes.
And you can see more
information about that in the
"Building Adaptive Apps with
UIKit" talk from last year.
So now that iPad multitasking
is here, what has changed?
Well, the answer is not much.
That's all for us.
Enjoy the conference.
[Laughter]
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[Laughter]
>> Jacob Xiao: Okay, so, there
are a few important changes
that you want to keep in mind
to give your app a great
experience with multitasking.
And let's talk about
a few of those.
Let's start with orientation.
How many of you have
code in your app
that looks something like this?
It is okay.
This is a judgment-free zone.
This kind of code made a
lot of sense in the past,
to give your app a different
layout when it was in portrait
or landscape, to really make
the best use of the space
that was available to you.
But you want to think
about how that should work
with iPad multitasking.
For example, here, although the
iPad itself is in landscape,
we don't really want to
use the landscape version
of our layout here,
because we have
so much more vertical space.
It makes a lot more sense
to use the previous layout
that we would have called
the portrait layout.
So with multitasking it is
better to avoid thinking
about things in terms
of the interface
orientation specifically.
Let's take a look at
what you can use instead
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Let's take a look at
what you can use instead
for these kinds of changes.
To get a better idea of this,
let's take a closer look
at what happens during rotation.
First let's take a look
at an iPhone rotation.
As the device rotates,
your app is resized
and rotates along with it.
But we can actually break
apart this transition
into two changes
that make it up.
First, your app is resized
to be the new content size,
and then it is actually
rotated to face
where the user is looking.
Now we can do something
similar with rotation
on iPad including
with multitasking.
Once again, this is what the
rotation itself looks like,
and we can break it apart into
first, that content resize,
and then, the rotation.
Now, when the user is
actually viewing this rotation,
these two changes
happen at the same time.
But it is useful to think about
them as two independent changes.
And one of the great
things about doing that is
that you can really share a
lot with multitasking resizes.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that you can really share a
lot with multitasking resizes.
Here the same kind of
thing is happening,
but just the resize
portion, not the rotation.
So as the user resizes your app,
it is just a content
bounds size change.
So, in the past, if you were
using the interface orientation
explicitly, I would
encourage you instead to think
about how you want to deal in
terms of the view size changing
for these kinds of
layout changes.
Another good option to
consider is the vertical
or horizontal size
class, and by using either
of these approaches
your app will work great
with multitasking.
So next, let's take a
closer look at transitions
like rotation and
multitasking resizes.
Previously we had callbacks for
your app related to rotation.
But these callbacks work
specifically in terms
of the interface
orientation changing.
So instead, in iOS 8, we
introduced new callbacks related
to the trait collection
or the view size changing,
and we strongly encourage
you to use these instead.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and we strongly encourage
you to use these instead.
Now, to get a better
idea about how this kind
of rotation transitions happen,
let's take a look at a timeline
of one of those transitions.
Let's start with rotation.
Now we can divide this
rotation transition
into a few different stages.
First, we'll set up for the
change that's about to occur.
Then, we'll create the
animations we'll be showing
to the user.
And then we'll actually
run those animations.
And this stage is the part
that the user actually sees
as the rotation happened.
Then, when everything is done,
we'll perform some clean up.
Now the point during this
transition where the size
and size classes actually
change for your app,
is just at the end
of the 'setup' stage.
So now that we have seen
the different stages
of this transition, let's see
how those callbacks fit in.
Both of the transition
callbacks happen as part
of the 'setup' stage
of these transitions.
Now, similarly, as the
size class is changing,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, similarly, as the
size class is changing,
the 'trait collection did
change' method is called
on your views and
view controllers.
Now the two transition
callbacks will not only give you
information about the change
that's about to occur,
they also pass your app
a transition coordinator.
And transition coordinators
have great API that you can use
to add your own alongside
animation blocks to be run
as part of the main animation.
And if you do those,
they'll be set
up during the 'create
animations' stage.
Similarly, if you
add completion blocks
to the transition coordinator,
those'll be run at the end,
as part of the 'cleanup' stage.
Now, notice that there
aren't any callbacks
to your app during the 'run
animations' stage specifically.
And that's because it
is generally better
to perform the work that
you want to do either
at the very beginning or the
very end of these transitions.
So now that we have seen
the rotation transition
and the timeline for what
happens, let's take a look
at a multitasking resize.
Now, during this transition,
we first perform some setup,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, during this transition,
we first perform some setup,
then we create some
animations --
well, hopefully you
see the pattern here.
These are the exact same
stages, and the callbacks happen
in the exact same way
with multitasking resizes.
And that's what's really great
about these new callbacks.
They allow you to use the
same code between rotation
and multitasking resizes.
Now, there is one
important thing to keep
in mind specifically
about resize transitions.
And that's that your app has
only a limited amount of time
to perform the changes
that it wants to do.
Just like with app start up,
if your app takes too long
to make these changes,
then it will be terminated.
But I'm sure that won't
happen to any of you.
So, one important
thing to keep in mind,
if you're implementing
both of these
to your transition callbacks,
is that 'will transition
to trait collection' will
be called before 'view will
transition to size.'
And this is useful
to keep in mind.
However, as Peter
mentioned earlier,
there are some multitasking
resizes
where only the size
will change in your app
and the size class
will stay the same.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and the size class
will stay the same.
When this happens, the trait
collections don't change,
and so we won't call the trait
collection change callback
methods, we'll only call 'view
will transition to size.'
You can still use the
transition coordinator APIs
to add alongside animation
and completion blocks.
Now, similarly, there
are some cases
where only the trait collection
of your app will change,
but the size will stay the same.
This can happen, for example,
when you're overwriting
the trait collection
of a view controller.
So as you're implementing
these callbacks,
make sure that you don't
assume that just because one
of them is called, the others
will be called as well.
And that's transitions.
Next, let's take
a look at windows
and specifically UIWindow.
Generally, when your app starts
up, you'll create a new UIWindow
and give it a frame
that's equal to the bounds
of your main UI screen.
Now, when that happens,
if the user resizes your
app during multitasking,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
then that UI window's frame
will automatically be resized
to match the new
size of your app.
And that will continue as long
as the user is resizing
your app.
However, if you create
a UIWindow
that has a size that's different
from the screen's bounds,
then we'll leave that
window to have the same size
as your app is resized.
As Peter mentioned, the origin
of UI windows is in the top left
of your app even
as they're resized.
So all of these UIWindows
will move along
with the rest of your app.
Now, generally, in the past, to
make a full-screen sized window,
you would create the UIWindow
and explicitly give it a frame
that was equal to the
main UI screen's bounds.
And you can still do that
with iPad multitasking,
but in iOS 9 we've
made this even easier.
Now you can just
create a new UIWindow
without passing any
explicit frame,
and we'll make it
the correct size
that your app is
using right now,
and automatically
resize it along
with all multitasking resizes.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Okay. Now let's take a
look at presentations.
In iOS 8, we introduced UI
Presentation Controller.
And this is a great class for
making custom presentations
or for working with
system-provided presentations.
And you can see "A Look Inside
Presentation Controllers,"
a talk from last year's
WWDC, for more information
about using this class.
One of the great things about
presentation controllers
with multitasking is their
support for adaptivity.
So, for example, you can show a
popover presentation on an iPad,
and when your app size
class changes, in this case
to the compact horizontal
size class,
it will automatically
transform that presentation
into a style that makes sense.
So, here, we have adapted to
a modal full screen style.
And this happens
between devices as well.
For example, if you perform
that same popover presentation
on an iPhone, it will
automatically show it
as a modal full screen
presentation there as well.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
as a modal full screen
presentation there as well.
On an iPhone 6+ in
landscape, we'll also make
that presentation a form
sheet presentation for you.
And all of these changes happen
automatically in your app just
by using 'view controller
presentations.'
However, you may
want to interact
with how these changes
occur as well.
For example, in this app,
as we're showing a popover
presentation when we're
in the modal full screen
style, we'll want to show a
"Done" button inside
of a navigation bar
so that the user can
dismiss this presentation.
But when we're using the native
popover presentation style,
we don't need to show
that "Done" button,
since the user can just
tap anywhere outside
of the popover to dismiss it.
And we can make these
kinds of changes
with the 'adaptive presentation
controller delegate' API.
In fact, we introduced
some new methods
to this protocol in iOS 8.3.
These methods allow you a lot
of control over the changes
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
These methods allow you a lot
of control over the changes
that happen as your view
controller presentation
is adapted.
So you can do things like
hide and show navigation bars
or whatever other changes
make sense for your app.
Now, one last thing to
keep in mind specifically
about popover presentations,
it is to always make sure
that the arrow from
the popover points
to the right source
for that popover.
This is particularly important
as your app is adapting
between the horizontally compact
and regular size classes.
You can easily do this
with a popover presentation
controller API.
Either set the barButtonItem
or set the sourceView
in sourceRect.
So that's presentations.
The last thing I'd like to
tell you about is some changes
to the keyboard with
multitasking.
Now, when the user is
multitasking with your app,
if they tap on a text field,
like the search bar in Maps,
then the keyboard will actually
be shown over top both apps
that the user is
interacting with.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that the user is
interacting with.
And this means it is
really important for you
to consider whether you want
to move pieces of your app
out of the way of the keyboard
so that the user can
still interact with them.
You can do that by using the
UIKeyboard Notification API,
just as you had in the past.
You can use these notifications
to make changes to your app
like setting scroll
views content insets
or moving important UI
elements to stay visible.
So, for example, in this app,
we may want to move the comment
field and the ratings view
to still be visible by the user.
And this is a really
important change
because in the past
the only time
that your app would
interact with the keyboard is
when it had explicitly
shown it itself.
But now, with multitasking,
the other app
that the user is using can
cause the keyboard to appear.
So you'll want to consider
whether any of the views
in your app need to move pieces
of their UI to stay visible
as the keyboard is shown.
So those are some
changes and best practices
for iPad multitasking.
A few important things to
remember are to consider size
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
A few important things to
remember are to consider size
and size classes
instead of orientation
as your app is rotating.
And to think about how you shall
want to respond to transitions
like rotations and
multitasking resizes.
And finally, to use
adaptive presentations
to make your app work great
on all of our devices and all
of the different
contexts that it is used.
Now I would like to
turn things over to Kurt
to tell you how you can make
the most out of multitasking.
[Applause]
>> Kurt Revis: Thank you.
Thank you, Jacob.
Thank you, Peter.
So now you know how and why
your app can adopt multitasking.
You know what's changed
-- not much.
You know what to
do, what not to do.
So I'm here to tell you how
your app can make the most
out of multitasking and
deliver a great experience
to your users.
So really your app needs to
be designed for adaptivity.
And I'll reiterate three
things we talked about earlier.
First, your app should
be universal;
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
First, your app should
be universal;
your app should run
on iPhone and iPad.
Second, don't think of those
user experiences as being iPhone
and iPad anymore; think of
them as being for compact
and regular widths, because now
that compact width experience
can happen on the iPad.
And then last, use adaptivity
to change between them
when the user changes
the size of your app.
So, the challenge when designing
for adaptivity is
making your app adapt
to these dynamic size changes.
And I'll give you two things,
actually six strategies
that your app can adopt in
order to make it flexible
and make it handle dynamic size
changes, and then I'll talk
about some finer points
that will come up,
some things you will run into
when you adopt multitasking
and some guidelines of how
to handle those things.
So let's get started.
The first strategy: be flexible.
Don't hard code sizes.
Don't make assumptions.
Your app should look
at what size it is
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Your app should look
at what size it is
and do something based on that.
And it should also react
to changes in its size.
So the only way to find out
if your app is really flexible
or not is really to try
it out, try stretching.
So let's do a little exercise
here, a little warm-up.
You will find there's a yoga
mat under your seats in front
of you, so please get that out!
No. Unfortunately, I'm only
talking about your app.
But we'll do the same thing.
We'll take your app
through a warm-up exercise.
We'll run through all
the multitasking cases
and we'll watch your
app's UI carefully.
Take notes.
What works; what doesn't work?
When you're doing this,
concentrate on the layout
of what your views are,
don't worry so much
about the animations
or anything like that,
especially if you're
doing it in the simulator,
because the experience will
be different on a real device.
So let's start.
Your app has adopted
multitasking
and you can start
it by sliding over.
Then resize your app bigger.
That's a size change.
Make it bigger again.
It will be full screen,
another size change.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now Slide Over another app
and press the button
to use Split View.
Your app will get smaller.
Finally let's rotate the whole
iPad, so we'll get a size change
and the rotation will happen,
the orientation will change,
and that will be animated.
So these are all things
that can happen to your app
and you should try out every
place everywhere in your app
to make sure that it
can handle these things.
When you try this, probably
you'll find some things work,
some things don't.
So for help on fixing the things
that don't work, keep listening.
The second strategy:
use Auto Layout.
This should be no
surprise; this is the way
to make your app's UI flexible.
All you have to do is
provide views and constraints,
the system will consider
all those constraints
and set your views'
frames based on those.
So you don't have to
hard code anything.
You can also use the margins and
the guides that UIKit gives you
to construct these constraints.
And also in iOS 9,
there's new APIs
to make this whole process
much more convenient.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to make this whole process
much more convenient.
So, to find out more about that,
see the two Auto Layout talks
on Thursday; I guarantee
you'll learn a lot.
So let's run through this
example that we saw earlier.
We have -- excuse me.
We have this app
showing some text,
and it is using those
readable margins.
Now, how this works is
your view size is large,
but the readable
content guide is smaller.
We don't want your
app to have to worry
about thinking, 'This
is an iPad.
It is big; it is wide.
I need to handle these
margins differently.'
You just use the guide and
it will work automatically.
So here is how to
do this in code.
First, make a label; we'll
put our text inside of that.
Second, the label goes
in some super view
and we'll get the
readable content guide
from that super view.
Now we'll set up some
constraints to make
that label match that
readable content guide.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So the constraints is an
array, and the first one
that we do is make the
label's leading anchor,
that's the leading side,
equal to the readable content
guide's leading anchor,
the leading side.
This is, note -- note that
this is using the new iOS 9
convenience API.
We do the same thing for the
trailing anchor on both sides.
So now, that label's width
will match the readable content
guide's width.
Then all we have to do is
activate those two constraints
and Auto Layout does the rest.
We didn't have to do anything.
So I could have also
done this in Xcode.
I could have set this up in
my storyboard, which leads me
to the next strategy:
take advantage
of the size class
support in Xcode.
You can set up your UI
to do different things
in different size classes.
For instance, using
interface builder
when you're editing a storyboard
or a XIB file, you can add
or remove user constraints
from different size classes,
and you can also
change the attributes
of views like the font size.
You can also take
advantage of asset catalogs
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You can also take
advantage of asset catalogs
to make different versions
of images that are used
in different size classes.
And note that this
applies not only
when you're initially loading
your UI the first time,
but also when dynamic
size changes happen.
We remember all of this
stuff behind the scenes
and we'll apply these things
when a size change happens.
So I'll give an example.
Here I've made this
storyboard and I've set
up a UI with two views.
There is an image and some text.
I put them side by side; I made
the constraints to do this.
I'm working on the
default UI for my app;
that's using the
'any width' class.
I would like to make a version
that's a little bit different
for compact width class.
So what I do is I
click that control,
I change it to compact width.
I have got the same two views,
but I changed my constraints
around to make the
layout different.
Now the image is on top,
the text is on the bottom.
I did that by clicking
that control at the bottom,
changing it to compact, and you
see there's blue telling me I'm
in a different, more
specialized mode.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now I could at this
point run my app
and try resizing it
and see what happens.
But the nice thing is I don't
actually have to do that.
I can see a live
preview inside of Xcode.
Just use the assistant pane in
Xcode and you can bring up more
than one preview at a
time of your storyboard
in different configurations.
So here I have got
iPad one-third width,
that's what happens when
you Slide Over your app,
that's using the compact layout.
At the same time I'm looking
at iPad full screen,
the other layout.
So you can make as many of
these previews as you want,
just press the "+" button in
the corner, and choose any size
of iPhone, any size of iPad
multitasking configuration.
You can see them all at
once and they're all live.
We can also use asset catalogs.
I'll show how that works.
Here I've got an asset catalog;
I'm looking at one
particular asset.
I'll set this thing
up to be universal;
it'll work on all devices.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
it'll work on all devices.
And then I'll do much the
same process as before,
I'll set up two different
versions of it.
One for any width, the default.
And one for compact width.
Now you see I have got
those two images there,
that's the two different
versions.
I can drag in a large
star to work
for the any regular
width configuration.
I drag in a smaller image
to be the compact width.
So that's Xcode.
Now, you can also drop down
and do this in texture,
in code yourself, if
you would like to.
Just take advantage of
the adaptivity callbacks.
So here is how to do this.
If you are in a view controller,
you would override 'will
transition to trait collection.'
We'll give you the
new collection
that we're going to change to.
Or you can override 'view
will transition to size,
and we'll give you the new size
that we're going
to transition to.
Now let's say I want my app
to have different UI depending
on the horizontal size class.
That's pretty normal.
How we'll do that is
override 'will transition
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
How we'll do that is
override 'will transition
to trait collection.'
And the first thing we
should do is call 'super,
let the system do what it
would normally would do.
Then we'll add our code.
We'll look at the new
collection's horizontal size
class, and depending
on what that is,
we'll do something different.
So here is where you
put your code in.
If it is compact, change
your UI for a compact width.
If it's regular, change
your UI for a regular width.
If it's unspecified, that
means we're in the middle
of setting things up
or tearing them down,
and just don't do anything.
Now let's say I have that
similar change, but I want it
to animate alongside other
things, like the case
when I rotated the iPad,
I would like my change
to animate alongside that
rotation, at the same time.
Here is how.
We start out exactly
the same way.
Override the same
method; call super.
Then, instead of making
the change directly,
we'll provide a block and
we'll put our changes inside
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
we'll provide a block and
we'll put our changes inside
of that block.
So, here we've got a
block, called 'animation,
and we'll put our code to
change the UI inside of there.
Then pass that block
to the coordinator's 'animate
alongside transition' method.
It will take care of remembering
that block and calling it
at the right time, once
the animation is set up.
And any changes you make inside
that block will automatically
get animated.
So that's how to do it at
the low level, in code.
I'll talk about some
of the high-level API
that UIKit provides to you.
First, as Jacob mentioned
earlier,
there is adaptive
presentation controllers.
Second, there is the classics --
UI Table View, UI
Collection View.
These let you build up a
larger UI out of small things
like a single row or a
single item in a collection.
Also new in iOS 9,
there is UI Stack View.
This lets you take a list
of views and put them
in a vertical stack
or a horizontal row,
and set up some parameters
on how they get laid out.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and set up some parameters
on how they get laid out.
Again, to find out
more about that,
check out the first
Auto Layout talk.
The last bit of high-level API
is big enough it deserves its
own number.
And that's UI Split
View Controller.
We use this in a lot
of our apps like Mail
and Messages and Notes.
And if it makes sense
for your app too, use it.
I'll give you Mail
as an example.
Here we're looking at full
screen iPad and you see
that the app is divided
into two parts.
And note that this
isn't the same thing
as split view multitasking where
you're looking at two apps.
This is one app.
So, we have on one side a
list of messages to look at.
You can pick one.
On the other side, we have a
view that shows the details.
In this case it is a
particular message.
So if your app can handle a
configuration like that or works
that way, we really
highly recommend
that you adopt Split
View Controller,
because it will do a lot of work
for you in multitasking cases.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'll show you that
a little bit later.
But first, here is
how you adopt it.
You make a UI Split View
Controller in your app.
That's typically the
root view controller,
so the top level of your UI.
And it is a container view
controller, so it has children.
We call these the primary and
the secondary view controllers.
In Mail, these are a table
view that contains that list
of messages, and on
the secondary side,
a custom view showing a message.
In your app you fill these in.
You provide the view
controllers.
UI Split View Controller is
responsible for deciding where
and when to show these
two view controllers.
Going back to Mail, in full
screen we have got lots of room;
we can show both of
these side by side.
What happens if the user
switches to a different app
and then slides Mail
over in from the side?
In that case it is a compact
width, there is less room,
so the Split View
Controller adapts to this.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
so the Split View
Controller adapts to this.
It decides it will show the
secondary view controller
to start that mail message,
and it also provides
navigation controls to go back
to the other list,
the primary list.
Once the user picks one of
those, they can go forward again
to the secondary list.
So those view controllers
are still independent;
they didn't have to make
any of these choices.
So the thing to note here is
that these are the same
exact two view controllers
that we were looking at earlier.
The differences are, they're
smaller, and we're navigating
between them in a different way.
So if you want to try this out,
you have already got the code
on your computer, in fact.
Just make a new Xcode, in Xcode
make a new iOS application,
and use the 'master-detail
application' template.
It is automatically set
up with a storyboard
that contains a Split
View Controller
and view controllers
for each side.
You can build on this
to make your own app
or you can just use it
as a test bed to play
with Split View Controller
and see what it can do.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with Split View Controller
and see what it can do.
So those are the 6
strategies I'll give you.
And please mix and match these
however makes sense in your app.
You can take a look
at our sample code
to see all of them in action.
This is an app called
'Adaptive Photos.'
You can search for it
on the developer site.
Try it out in all sizes
of iPhone and iPad
and iPad multitasking
and see what it can do.
So that's the strategies.
If you use these, your app
will start resizing nicely;
it will probably
work pretty well.
But you will run into some
new things that happen.
So once you adopt multitasking,
these new things may
be a little tricky.
I'll give you some guidelines
on how to handle them.
The first guideline,
most important,
the user controls
your app's size.
The user is always in
control of how big things are.
So your app cannot prevent
size changes from happening.
I know sometimes
it is inconvenient
but your app can't prevent it.
Also your app can't
cause a size change.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Also your app can't
cause a size change.
You can't say, 'My app wants
to be full screen now.'
It doesn't work that way.
And we really do mean that size
changes can happen at any time.
The user might choose to
resize the apps any time.
It's just like pressing
the Home button.
They can do that any time.
So how do we react
to size changes?
Well, our guideline is
keep the user oriented.
Don't let the user get lost.
I'll illustrate that with a
concrete example of a real app.
I have got a To-Do List app.
It has got a bunch of
items I need to check off.
And I have got them
in three categories:
home, work, and school.
Now I'll put on my designer hat
and I'll choose to make some UIs
for regular width
and compact width.
In regular width, I think,
'Well, it makes sense
to put these all
in a scroll view.
We'll put them on
top of each other.
We'll let the user
scroll through them.'
In compact width, I think,
'Well, let's just show one
of these categories at a
time, each on a separate page,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of these categories at a
time, each on a separate page,
and let the user scroll
from page to page.
But only one is visible
at a time.'
So that's great.
I have got two UIs.
But now I need to think
about how to change
from one to the other.
Let's say I'm looking
at School right now.
And the user resizes the
app to be regular width.
What do I do?
Well, by default, if I just
go and make a new scroll view,
and put my stuff into it, it's
probably going to be scrolled
to the very top, at (0,0),
and now School isn't
visible anymore.
So the user might get lost.
We don't want to do that.
The app should choose and make
a good decision and scroll
so that the same thing
is visible again.
So School is visible.
This doesn't happen
automatically; your app needs
to make this kind of decision.
Let's say the user keeps
working with the app,
they scroll down a little bit.
They write some code;
they check that off.
Great. Wrote some code today.
And then they decide to
resize the app to be compact.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
What do we do?
You will see that all three
categories are visible
on the screen at the same time.
So we could make a case for
any one of them to be visible.
But in this case it
probably makes sense,
since they last checked
something off in Work,
and they're still looking at it
and they haven't
controlled away,
that we should choose
to go to that page.
But again, that's a
decision the app had to make.
And your app will have to
make decisions just like this.
So to keep the user oriented,
don't make abrupt changes
when the size changes
from one thing to another.
Try to keep the same
things visible.
You might have to be
smart in new ways.
You might have to do
something like keep track
of what the user most
recently looked at or touched
that you didn't have
to do before.
And also it is especially
important when you're going
from large sizes to small sizes,
because you can't show all
of the stuff that you
were showing before.
So speaking of resizing,
here is another new thing
that can happen with --
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
once your app has
adopted multitasking.
Let's say your app
becomes inactive;
the user presses
the Home button.
After that happens, your
app's size may change.
The system might want
to take a snapshot
of your app in a different size.
When that happens, the
same adaptivity methods
as before will get called,
but nothing will be visible,
the user won't see any of this.
When it is done, the
system will restore you back
to the original size.
Now this can be a little
tricky to deal with,
but I'll give you some
guidelines on how to handle it.
And I'll show you
a concrete example.
I have got my app again.
I'm active; it is
in compact width
and I'm looking at
that Work page.
Now the user presses
the Home button.
And the system will take
a snapshot right now.
Now, this is not a new thing; we
have done this for a long time.
What's going to happen is
the user takes that snapshot
and then when the app comes
back active, we'll first show
that snapshot and then we'll
fade into the live app as it is.
So remember this
snapshot right here,
we're purple, we're at Work.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
we're purple, we're at Work.
Now, with multitasking, the
system will resize us to regular
and take a snapshot
for its own purposes.
And now the system is going
to resize us back to compact.
Now here is the point where
the app has to make a decision.
And I'll show you what happens
when we make a bad decision
and then a good decision, and
the ramifications of both.
Let's make the bad
decision first.
We go back to compact,
and my app decides, 'well,
Home was at the top, so
we'll show Home again.'
The app stays inactive for
a while; the user comes back
and activates the app.
Then the system shows that
snapshot again from Step 3.
Remember, we were at Work.
It's purple.
It's that same snapshot.
And now the system will
crossfade from that
into the live app,
which is at Home.
So that looked bad.
It was a really ugly
animation, and it didn't use --
do what the user wanted.
They were in one place,
they left the app,
they came back, it
is somewhere else.
That's no good.
So what we should do,
backing all the way up....
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So what we should do,
backing all the way up....
We're in regular width;
the system is going
to resize us back to compact.
We should resize -- we should
change the app back to the state
that it was in when
we were inactivated.
And then going forward,
user activates the app;
system shows the snapshot;
it is the same thing.
We fade into the live
app, it is the same thing.
It is seamless.
So that's the way you
want to handle things.
When the app is inactive,
maintain the same appearance
when the size changes.
You can do this by, when
the app is deactivated,
remember your size and state,
remember what page you're on.
When you get a size change,
and you're still inactive,
and it is sizing back
to that original size,
then apply that state
that you remembered,
go back to that original page.
So we're down to the last two
guidelines, and these will touch
on some things that we'll talk
about in the later multitasking
talks, but first I need
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
about in the later multitasking
talks, but first I need
to introduce some terminology.
So, there is two apps running.
The primary app is the one
that starts out in full screen;
it is what you think
of traditionally
as the app that's running.
When you Slide Over another app
we call that the secondary app.
Now no matter how you resize the
apps, they keep this identity;
they're always the same.
And normally we treat these
apps exactly the same.
There really are not
too many differences.
The differences come in when
we're talking about resources
that can't be shared
easily across both apps.
One of those might be
an external display.
If you plug in a TV to your
iPad or use Airplane Mirroring
with an Apple TV, you can
show UI both on the iPad
and that external display.
With multitasking only the
primary app will see the
external display,
not the secondary --
not the secondary app.
So normally apps that use the
external display will split
their UI across the iPad
and the external screen
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
their UI across the iPad
and the external screen
when a screen is activated, when
the user plugs something in.
And they are expecting that.
They just plug something in and
they expect something to happen.
There is a quirk with
multitasking now though.
Let's say your app
is the secondary app
and the user quickly resizes
it to become the primary app,
once it is full screen.
When that happens, your
app will get a notification
that that screen
is now available,
the external display
is now available.
And if your app chooses
to immediately take its UI
and split it across the
iPad and the other screen,
the user might not be expecting
that, depending on your app.
So try that out in your app.
Make sure you do something
that makes sense to the user.
The last guideline
is about performance.
And, again, we have
a whole talk on this,
so I'll only touch
on some high points.
As we said before, if
your app doesn't react
to a size change fast enough,
it will get terminated.
So when the size
changes, do as little work
as you can get away with.
If you have anything slow to
do, use the completion block
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If you have anything slow to
do, use the completion block
and 'view will transition
to size'
or 'will transition
to trait collection.'
And also, in the
animation block,
don't do any extra layouts;
don't call 'layout if needed.'
The system is going to do a
layout at the appropriate time,
and take advantage of that.
Just call 'set needs layout'
and let the layout happen,
because layouts can
be time consuming.
So that's the strategies;
that's the guidelines.
Now you know a lot about how
to make your app work
great with multitasking.
Now you know how and why to
adopt multitasking in your app.
You know that adaptivity
has been around since iOS 8;
it is not a big stretch
what we're doing in iOS 9.
And you know how to deliver
a great user experience.
You have the technology.
So your users want to use
multitasking; let them have it.
For more information, check
out our documentation,
especially "Adopting
Multitasking Enhancements
on iPad."
Check out our sample code.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Check out our sample code.
You can talk to tech support,
the developer forums, DTS.
For general inquiries, talk to
Curt Rothert, our Evangelist.
And if you have more questions,
we have more sessions.
Again, if you want to find
out about picture-in-picture
or sharing the camera, go
to "Multitasking Essentials
for Media-Based Apps."
If you want to find out
how to be a good citizen
and share resources like CPU
and memory across the apps,
go to "Optimizing Your
App for Multitasking."
Last, visit us in the "Cocoa
Touch and Multitasking Lab."
We'll help you out
with your app.
So thank you for coming.
Go forth and multitask.