WWDC2019 Session 214

Transcript

[ Music ]
[ Applause ]
>> Good morning.
Welcome to Implementing Dark
Mode in iOS.
I'm Kurt. I'll be presenting
with Tyler.
Now, when we added Dark Mode to
iOS 13, we looked at every piece
of the UI and made it look great
in this new dark appearance.
It's a whole new look for iOS.
Now it's your turn.
We're here to help you implement
Dark Mode in your apps.
It's easy and we'll demonstrate
that to you with some live
demos.
It's also built on top of a very
flexible and powerful system.
So whatever you imagine that
your app should look like in
Dark Mode, you can achieve it.
First, let's talk about the
design of Dark Mode.
Now, I'll start by showing an
example.
Here's settings of a very
familiar app.
You see that in Dark Mode, it's
the same app in the same layout.
It works the same way.
It just has a different
appearance.
So, we've taken the iOS design
system and extended it for the
dark appearance.
When we did that, we considered
three things.
First and most important,
colors.
iOS apps traditionally have hard
coded all of their colors.
You specify the RGB value of
every piece of your UI.
Now that we have Dark Mode,
almost every one of those colors
needs to change.
And since there are so many
colors, we need to keep
organized.
We do that using semantic
colors.
These are colors that have a
name that explains what they
signify.
Our text label here uses the
color label.
That's a default color for text
and labels.
Our background is system grouped
background.
That's because we're in a
grouped table view, and UI table
view gives us that by default.
Finally for this icon, we're
using system blue.
It's not just pure blue, but
it's tweaked to fit with the
rest of the colors.
So, when we implement UI, we
pick an appropriate semantic
color for each piece.
When we switch back to light
mode, we're still using the same
colors.
But because these colors are
dynamic, they can have different
values in light and dark.
The great thing is when you use
these semantic dynamic colors,
UI kit does the work for you.
You don't have to think about
what mode you're in and you
don't have to do any work when
the mode changes.
Now, our design system provides
a whole new palette of colors.
I'll give some examples.
We have a stack of background
colors here designed to work
together.
System background is the base
background color, it's pure
white in light mode.
That's very familiar, and pure
black in dark mode.
On top of that, there's
secondary and tertiary system
background colors, and these
allow you to structure the
information hierarchy of your
app.
Note that dark mode is not just
a simple inversion of light
mode.
It's more subtle than that.
We use this idea of hierarchy
for text as well.
There's four levels of text
colors and they let you
emphasize which elements are
important relative to others.
For instance, the primary color
might be used for things like
titles.
The secondary color might be
used for subtitles and so on.
The full catalog of colors is in
the human interface guidelines,
what they are and when to use
them.
And we provide a lot of colors
but you will need to make your
own.
You can make your own dynamic
colors and we'll show you how to
do that a little later.
Now, let's move on to the second
part of our design system -
materials.
Here's an example in photos.
Materials are more than just
colors.
There are blur effects that look
like a translucent material on
top of a background.
On top of that, there's vibrancy
that cuts through the blur and
stands out.
Of course these look good on top
of any photo that we have, and
they work in dark and in light
mode.
The third part of the design
system is the built-in views and
controls provided by UIKit.
These are made using the same
colors and the same materials.
Everything has been designed to
fit together.
So, when you design your app for
Dark Mode, before you touch a
single line of code, learn this
design system and figure out how
to take advantage of what it
provides.
Then, figure out what you'd like
to customize.
iOS apps have so much diversity
that we can't provide everything
for you, but we do give you the
power to do anything you need.
So, now that you've thought
about your design, let's talk
about how to implement it.
As soon as you build using the
iOS 13 SDK, your app can appear
in Light and Dark.
Switch the device to Dark Mode,
run your app, and see what it
looks like.
The first thing you'll find is
that you do have work to do.
We can't do this for you
automatically.
And ultimately it is your
responsibility to make the
choices to make your app look
good in Dark Mode.
The first thing you'll need to
do is start with colors.
Now in the past, each UI color
had only one single value.
It was always the same.
Now they can be dynamic.
The color can have a different
value in Light Mode and in Dark
Mode.
And when you set one of these
dynamic colors on a view, for
instance, as a background color
or a text color, UIKit will
automatically use the correct
value and will update when the
mode changes.
So, you just set the color once.
If you're familiar with macOS
Dark Mode, this is how NSColor
works.
We're following the exact same
pattern.
So, let's get started.
Let's implement Dark Mode in an
app.
Over to Tyler for a demo.
[ Applause ]
>> Thanks, Kurt.
So, we have a simple demo app
that we put together which was
originally written against iOS
12, and we want to walk you
through some of the changes that
we'll make to update this to
support Dark Mode in iOS 13.
This should hopefully give you
an idea of some of the types of
changes that you'll be making in
your own apps.
So, here's our app running in a
simulator on the right.
It's pretty simple.
So, why don't we just start by
flipping it into Dark Mode and
seeing how things look.
We can do that using the new
environment overrides feature in
Xcode.
So, we're running from Xcode
here.
We can just apply a dark user
interface dial override by
toggling that switch.
And if you noticed, our app
reacted right away.
It turned into Dark Mode.
Now, you might've noticed that
for example the tab bar at the
bottom of the screen changed.
And that's because we're using a
UIKit standard tab bar, so we
got all of that for free.
But of course our app didn't
rally get very dark and that's
because we have some work to do.
So, why don't we switch over and
take a look at how our UI is
built in the storyboard.
So, here's our home screen of
our app.
And the first thing that we
should probably take a look at
is why we have this white
background sitting behind
everything.
We can select that view in our
storyboard here.
And if you look in the
attributes inspector on the
right, you can see that we're
setting a hard-coded white
color.
That might've been fine before,
but we now want to switch to
using one of these new dynamic
colors that Kurt talked about.
So, a great choice is the system
background color.
So, you can find all these
system colors in this new list
here.
We'll choose system background.
And nothing actually changed
when we did that, and that's
because system background color
is still white in light mode.
But what we can do is write in
the storyboard editor, switch
our preview to see what it's
going to look like in Dark Mode.
So, if we do that, we can now
see that we're getting a dark
background color here.
But of course, our text just
disappeared.
What happened?
Well, we have black text drawing
on top of a black background.
So, we need to actually go in
here and we can choose, let's
start with the title label.
And we can see on the right that
we have this configured also
with a hard-coded black color
for the text.
So, once again, we need to
switch that to one of these new
dynamic colors.
In this case, we have a great
choice with the label color.
That's going to give us white in
Dark Mode.
Similarly, we select our text
view.
It's also set to black, so we'll
need to update that as well.
So, now that we've made those
changes, how about we run in the
simulator and see how things are
actually starting to look.
Here's our app running in light
mode.
We'll once again go to those
environment overrides and toggle
it into dark.
And now we're seeing a lot more
updating.
And so it's looking pretty good.
But what if we want to go a
little bit further?
So, at the top we have this star
image.
That's our app's logo.
And we want to customize that
with a different color in Dark
Mode.
So, this is easily possible.
We can select the image in our
storyboard.
You'll see this is an image
view.
It's configured with an image
that comes from our asset
catalog.
And this image is set up to
render as a template image,
which means that any tint color
set on the image view is going
to tint the image.
So, here we're tinting it with
this custom logo color that
we've already defined in our
asset catalog.
Let's click this little arrow
right here to jump straight to
that color and see how it's set
up.
So, here's that color.
It's this custom green color.
If we want to add a different
appearance for Dark Mode, we can
do that now by opening up a new
slot specific for the dark
appearance.
Once we've done that, we can
select the dark appearance and
change it, let's say to a nice
yellow perhaps, something like
that.
And now we have a color set up
to automatically switch between
two different appearances in
light and dark.
So, if I save and switch back to
our storyboard, you can see that
as we toggle between light and
dark in the preview, we're
getting that automatic updating,
which is great.
[ Applause ]
But there's more.
What if we want to actually
update that background image?
So right now it's a nice
tropical beach scene during the
day.
Wouldn't it be cool if it kind
of got to a nice sunset-darkened
appearance in Dark Mode?
We can select that image view
and do something really similar
to what we did with the color.
So, here we have an image view,
it's configured with this header
image in our asset catalog.
We'll click the arrow to jump
directly to that.
Here's where that image is set
up.
And just like you saw with the
color, it's really just the same
thing.
You can open up a new slot for
the dark appearance and then all
we need to do is grab that
sunset image, drag that in.
I'll save and just let's run for
real and see what everything
looks like in the simulator now.
So, this is light mode.
Nothing has changed.
It's all what we started with,
even with all these changes.
But once we flip into Dark using
our environment overrides, now
everything on this screen has
been updated to support Dark
Mode.
[ Applause ]
So the really cool thing that
you've seen here is that by
using all of these dynamic
colors and taking advantage of
these dynamic images and custom
colors in the asset catalog, we
were able to get Dark Mode
working without any code.
This is the advantage of taking
advantage of all of this
infrastructure that we provide
for you in Xcode and UIKit.
You can also make these same
sorts of changes to your app's
Launch storyboard to support
Dark Mode when your app is
launching as well.
So, now why don't we take a look
at another screen in our app.
If you tap this Learn More
button, we present a view
controller here in this new
card-style presentation.
And of course we're going to
want to make this support Dark
Mode as well.
The interesting thing here is
that on the bottom half, you can
see we're taking advantage of
some materials.
So, we have a blur over this
background image and then we
have a vibrant label sitting on
top of that.
I'll hand things back over to
Kurt to talk a little bit more
about how you can use these
visual effects to automatically
update for Dark Mode as well.
>> Thank you, Tyler.
[ Applause ]
So, let me show some examples of
these materials.
Here's some new blur effects.
There's thick, regular, thin,
and ultra thin styles.
And of course these work in
light and in dark.
Now here's how to use them.
Let's say in my app I have some
views in the background and I
want a blur on top of them.
First thing we do is create a
UIBlur effect, and we specify a
style.
In this case, we're going to use
system material.
That's a good default choice.
Next, we create a UIVisual
effect view using that effect.
We make sure its size and
position are appropriate, then
we put the visual effect view
into our view hierarchy.
You see that it blurs everything
underneath it.
It's pretty simple.
Now, on top of Blur effects, you
can have vibrant content.
The vibrancy effect let's some
of the background material pass
through.
And in the past, there was only
one style of vibrancy but now
there are several.
There's four styles for text,
three styles for larger filled
areas, and even a style for thin
separator lines.
Of course, these work in light
and in dark.
So, here's how to implement
vibrancy.
Now, vibrancy's always added on
top of Blur, so, we're starting
with the same setup from before.
We'll make a vibrancy effect and
we specify a style.
In this case, I'm using fill
because I'm going to show a
larger filled area.
Note that when you create a
vibrancy effect, you give it a
reference to a Blur effect.
The two things operate together.
To show the vibrancy effect, we
make another visual effect view,
and then we'll put that inside
the Blur effect.
Now, there's something a little
subtle here, is that we don't
ever add views directly as
subviews of a visual effect
view.
Instead, we go through its
content view.
Now we'll add the views that
become vibrant.
So again, I get the content view
and then I add the views that
will become vibrant and you see
how it looks.
In this case, our view has an
opaque background color.
But instead of its normal color,
you see the vibrancy effect
instead.
That's because with this
vibrancy style, the color is
ignored and only the alpha is
used.
So, over to Tyler again to
finish adding materials to our
demo app.
[ Applause ]
>> Okay. So, we're back on this
learn more screen and the
difference between this screen
and the last screen that we
worked on is that this one is
actually built entirely in code.
So, here we are in our view
controller, and you can see that
everything's assembled in this
Load View method.
Before we actually get started,
why don't we just try flipping
on Dark Mode and seeing how
things look.
We'll go here to our environment
overrides, switch to Dark, and
if you notice, there's actually
a few things that changed.
We got the navigation bar this
time for free, because that's
coming from UIKit.
We also already have our dynamic
custom color and the custom
image set up, and it's the same
ones that we updated before, so
those are already working as
well.
But of course, you can see we
still have a white background
and those materials don't look
particularly great in the dark
appearance here.
So, we're going to make some
changes.
So, let's take a look at how all
of this is built.
The first thing that we do is
set up this view in the
background.
This is where the white is
coming from.
Just like you saw in the
storyboard, we need to switch to
use one of the new system
background colors.
Let's choose system background
again, just like we did before.
Next we're setting up the star
image, and again, that's using
our asset catalog color.
So, nothing to do there.
Here is the learn more label
that you can see, the title of
this screen.
We're going to need to make a
change because we have the black
hard-coded color here.
And once again, we can just
switch to something like label.
Now, for the bottom half, what
we have going on is an image
view sitting at the very back.
That's right here.
Layered on top of the image view
is a visual effect view
configured with a Blur.
So, that's this light-style
blur.
Then on top of that, we have
another visual effect view
configured with vibrancy.
That's right here.
And finally, inside of the
content view of that vibrancy
view, we have the label.
So, the changes that we need to
make to update these materials
are first of all to switch to a
dynamic blur effect.
This light effect is not
actually dynamic.
It's not going to update for us
when we switch to Dark Mode.
So, we can take advantage of
this brand-new system material
palette that we have in iOS 13.
Great choice, because the system
thin material for this
particular use case, it'll look
very similar to what we had
before.
And then we also want to update
our vibrancy to take advantage
of the new system vibrancy
styles.
And these vibrancy styles now
come in a nice hierarchy.
So, we can add a style
parameter.
And in this case it's kind of
secondary content, so we can
choose the secondary label and
with those few changes, why
don't we run and see how things
look.
Let's bring up that
presentation.
So, here we are in light mode.
It looks pretty similar to what
we had before, but we'll now
switch into Dark.
And bam. Everything has been
updated with nice, new Dark
Materials.
[ Applause ]
So, one point here is that even
though we did write some code
this time, there's nothing wrong
with that, we didn't actually
need to write any code that
explicitly checked which mode we
were in, or handled changes from
Light to Dark Mode or vice
versa.
This is also the advantage of
taking-- of using these dynamic
system colors and materials in
your app.
I'll had it back over to Kurt to
tell you a little bit more of
how all of this works behind the
scenes.
>> Thank you.
[ Applause ]
So, here's something subtle that
you might not have noticed.
We used system background color
as the main background in our
app, that was black.
And then we used it again in
that presented view.
And if you look carefully, you
can see it's a lighter shade of
grey.
That's because the design for
Dark Mode has two different
levels.
When the view fills the whole
screen edge to edge, we call
that the base level.
And then when content appears in
a separate layer above that, we
call that the elevated level.
So, in Dark Mode, the
system-provided background
colors have lighter values in
the elevated level.
This helps distinguish them from
the black background underneath.
But foreground colors don't
change.
Now on iPhone, this can happen
with presentations, as you see
here.
On iPad, this can also happen
when the app is in multitasking
split view, so it doesn't fill
the whole screen.
So, we've learned the essentials
about implementing Dark Mode.
And we've both been saying that
things just work.
It's just automatic.
So, let's dive deeper into how
dynamic colors and images work.
And this will help you take
advantage of all this power and
flexibility.
So, we've seen how dynamic
colors automatically resolve
their appearance, but how does
the color know whether it's
light or dark?
This is done with trait
collections.
So, each view and view
controller in your app has a
trait collection, and this helps
determine the appearance of the
views.
In this case, all of our views
have the same trait collection.
The idiom is phone, because
we're running on a phone and not
an iPad or CarPlay.
The user interface style is
dark, because we're in Dark
Mode.
And the user interface level is
base, because we're full screen.
So, if you want to find out what
appearance to use, get the trait
collection, we'll look at the
user interface style, and also
the other traits.
Now, dynamic colors are resolved
using a trait collection.
So, it's the combination of a
dynamic color and a trait
collection that determine the
final resolved color.
And normally this happens
automatically but if you need
resolve a color yourself, you
can do that.
Let's say we have a dynamic
color and we've gotten a trait
collection from a view.
If we want to resolve that
color, we just say dynamic color
resolved color with trait
collection.
It will return a fully resolved
color that isn't dynamic
anymore.
So, this is safe to call on any
color.
If that color wasn't dynamic, it
would've just returned itself.
You can also make custom dynamic
colors.
We showed how to do that in the
asset catalog, but you can do
that in code as well.
Initialize a color with a
closure, and the argument is a
trait collection.
Then our closure will return
another color.
So, each time this dynamic color
needs to be resolved, that
closure will be called with the
appropriate trait collection.
And in the closure, you can use
that trait collection to
determine another color to
return.
This example is implementing the
diagram that we just saw.
So another question.
You might be wondering since
dynamic colors can be used
directly like any other color,
how did they get resolved
automatically?
If I have a dynamic color and I
ask it for its RGB components,
it'll return a result.
If I have black, I'll get 000.
Well, when I ask it, I don't
pass in a Trait Collection.
How does it know?
Well, there's a new property on
UITrait Collection called
current, and this is set for you
by UIKit.
And the color is resolved using
that current Trait Collection.
And again, we're following the
same pattern from the mac.
This is the same concept as
NSAppearance.current.
Now, UIKit sets the current
Trait Collection for you when it
calls certain methods.
Here's an example.
I have a UIVIew Subclass and
I've overridden the draw method.
So, this view will do all of its
own drawing.
Before it calls this method,
UIKit will set the current Trait
Collection to the Views Trait
Collection.
So that inside this code when a
dynamic color needs to be
resolved, it will use the Views
Trait Collection.
In fact, when the mode changes,
UIKit knows that you overrode
the draw method.
So, it will automatically call
set needs display on your view
and will draw again with new
colors.
UIKit also sets the current
Trait Collection for you before
it calls several other methods.
I'm-- subclasses of view, view
controller, and presentation
controller, explain draw.
But UIKit also sets the current
Trait Collection during layout.
So, override layout subviews in
your view subclass and then add
code that resolves dynamic
colors.
When the mode changes, set needs
layout will be called.
Layout will happen again.
And this includes the
corresponding calls on view
controller and presentation
controller.
Finally, all three kinds of
these objects get trait
collection did change, when a
trait changes.
And views get tint color did
change when the tint color
changes.
So inside all of these methods,
it's convenient to be able to
use dynamic colors right away.
Now, here's a big point to keep
in mind.
Outside of these methods, the
current trait collection is not
guaranteed to have any
particular value, so if you need
to resolve a dynamic color
outside of these methods, you
need to manage it.
Here's an example of why you
might need to.
Lower-level classes, like CA
Layer and CG Color, don't
understand dynamic colors.
It's a UIKit concept.
So in this case, we're creating
a layer and then setting its
border color.
That takes a CG Color which
can't be dynamic.
So, calling CG Color on a UIKit
dynamic color needs to resolve
it.
Now, let's imagine, we're not in
one of those methods I mentioned
earlier.
That means it's our
responsibility to manage this
process.
The first thing we need is a
Trait Collection and we'll get
it from a view.
Now we need to use that Trait
Collection, and I'll show three
ways to do this.
The first way we've already
seen.
Ask the color to resolve itself
using that Trait Collection.
Now this is fine if you have
only a single color, but it can
be awkward if you've got more.
And you have to remember to do
it every time.
The second way is easier.
Just call perform as current on
the Trait Collection.
That makes that Trait Collection
become the current Trait
Collection, and then it runs the
code in the closure that you
provide.
So, since we're resolving the
color inside that closure, you
get the right value.
Finally, the third option,
directly set the current Trait
Collection.
This looks a little intimidating
but it's absolutely safe.
It's lightweight.
There are no side effects.
This is even safe to do on a
background thread.
It will only affect the specific
thread that you're running on,
so it won't affect your main
thread.
If you're going to do this, it's
a good idea to save the current
Trait Collection and then
restore it afterwards in case
any other code was relying on
it.
And note that performance
current does that for you, it
does this exact same thing.
So, if you are doing this sort
of thing, you will also want to
know when the dynamic color
needs to be resolved again.
That usually happens when traits
change.
When traits change, Trait
Collection did change as called.
But not all trait changes will
affect colors.
If the user interface style
changes from light to dark, that
will obviously affect colors.
But if something like a size
class changes because your app
was resized, that won't affect
colors.
So, it's best to use this method
has different color appearance
to see if the relevant traits
have changed.
If it didn't, then you should
resolve those dynamic colors
again.
Finally, let's talk about
images.
As you saw, you can create
dynamic images in the asset
catalog.
And when you show one of these
images with UIImage view, it
uses its Trait Collection to
determine which image to
display.
Now, UIImage view is doing the
work here.
Unlike UIColor, UIImage doesn't
pay attention to the current
Trait Collection.
So, we recommend most of the
time use UIImage view.
But if you need to resolve the
color yourself, you can.
Given an image, just ask for its
image asset.
That's that collection of all
the different image variations.
Next, ask for a specific image
that matches a specific Trait
Collection.
You can also use the image asset
to register new variations of an
image at runtime.
So, if you draw your own image,
you can add variations for light
and dark.
Just put that in in an image
view.
It will automatically show the
right one.
So, let's talk about some things
to keep in mind when adopting
Dark Mode.
Over to Tyler.
[ Applause ]
>> Thanks, Kurt.
So, let's take a few minutes to
review some more things about
how Trait Collections work.
Because as you've seen, these
play a really key role in Dark
Mode.
The most important thing to
remember about Trait Collections
is that there is not just one in
your entire app.
Trait Collections actually
cascade through the hierarchy of
your app, starting at the root
level with the screen, then down
to the window scene, which is
new this year in iOS 13.
From there, down to the window.
At that point, traits start to
flow into any presentations in
your app and then the view
controllers inside those
presentations.
And finally, traits cascade
through the view hierarchy
inside each of your view
controllers.
Because of this hierarchy, you
always want to use the trait
collection of the most specific
view or view controller you can.
And when the value of a trait
changes, you're going to receive
trait collection did change on
all of these objects inside of
your app when they get that
change.
So, if the system Dark Mode
setting changes, for example,
you'll see that trait change
just cascade right through.
But I want to talk a little bit
more about Trait Changes,
because we have some new
behavior this year in iOS 13.
Let's zoom into the bottom half
of this diagram and walk through
an example about what's changed.
So, here's a view that we want
to add into the view hierarchy.
It's going to become the view
inside of this view controller
right above it.
The first thing that we'll do is
create that view.
Now, when a view is being
initialized, it hasn't yet been
added inside of this trait
hierarchy.
So, when the view's created, in
iOS 13, UIKit is going to make a
prediction about where it
expects that view will end up,
and populate that view's Trait
Collection right from the start
based on the predicted
destination.
So, now let's add this view
and-- yeah, it's pretty cool
[laughter].
[ Applause ]
So, let's add this view into the
hierarchy now.
So, we'll do that by calling out
subview.
It moves over.
And once the view's actually
added, it's going to inherit its
actually traits from its parent
trait environment, in this case
the view controller above it.
But in this case, since the
Trait Collection was correctly
predicted up front, there wasn't
a trait change that happened
when that view moved into the
view controller and view
hierarchy.
So, what you've seen is some new
behavior in iOS 13.
To recap, traits are now
predicted during initialization.
View controllers and views will
all receive a pretty complete
Trait Collection right up front,
which is really useful.
And then Trait Collection did
change will only be called
afterwards if any of those
initial traits change.
So, when you're updating your
existing apps for iOS 13, keep
an eye out for existing code
that you might have inside of
methods like Trait Collection
did change that expected the
older behavior where there was
often a trait change that
occurred when you moved into the
hierarchy.
Now, to make it a little bit
easier to see when some of these
trait changes are occurring in
iOS 13, we have some helpful new
debug logging this year.
You can enable using this launch
argument and it'll tell you
exactly when Trait Collection
did change is called and the
details of each of those
changes.
It's really cool and you should
give it a try.
Now, as you're updating your
existing code or adding new code
that uses traits, the best
practice is to wait until layout
to actually read the Trait
Collection from the view or view
controller and perform work
based on it.
Traits are always updated before
layout occurs.
And so if you get the Trait
Collection from inside of one of
these methods, you can rest
assured that it's not going to
be a prediction anymore.
It'll reflect the actual values
that it was inheriting from its
parent.
Just remember that if you put
code in any of these layout
methods, they can be called
often when the view is visible.
Anytime something calls, a set
needs layout.
So, be sure that you handle this
by not repeating work
unnecessarily.
So, that's what you should keep
in mind when using Trait
Collections.
But it turns out that we can
also modify these trait
collections inside of our app as
well.
Here's an example of why you
might want to do this.
Let's say that we want the learn
more screen that we showed you
in our app to always be dark,
even when the rest of our app is
in light appearance.
We can do this by taking
advantage of the trait
hierarchy.
So if this diagram represents
our app, normally with the
system in light mode, everything
will have the light user
interface style, just like you
see here.
But if we just want let's say
that one view controller on the
bottom right and everything on
the side of it to be dark, we
can do that by overriding the
user interface style trait with
dark.
And now everything inside that
view controller will be dark,
even the rest of our app and
even the system is running in
light mode.
So, how do you actually do this
override?
We have some new API this year
in iOS 13 to make this really
easy.
There are new properties on view
controller and view so that you
can just set the user interface
style that you want and it'll
apply to everything inside that
and all of its children.
Now, you should use the view
controller property whenever
possible.
The view one should only be used
if you don't have a view
controller around for that
particular thing you're trying
to change.
And there are some caveats if
you use that view property, so
be sure to read the
documentation if you do.
Finally, if your entire app
should always just be light or
dark, we have an info p list key
you can set to make this really
easy.
There's also some existing API
that you can use to override
traits.
This will let you override any
trait on a view controller or
presentation controller.
And the key thing to remember
when you use this is that the
override trait collection that
you set should only contain
values for the specific traits
you care about overriding.
Leave all of the other traits
unspecified - just don't touch
them - so that UIKit will
automatically fill in the normal
inherited values for those
traits.
That's pretty much all you need
to know to successfully use
Trait Collections in iOS 13.
Let's talk about some of the
other API updates that we have
this year and some other things
to keep in mind as you're
updating your apps to support
Dark Mode.
And how about we'll start with
the status bar.
Prior to iOS 13, we had two
existing status bar styles.
We had the default style and
light content.
New in iOS 13, we have a new
dark content style, which is
sort of taking over the place of
what used to be default, and
we've repurposed default to
become an automatic style
switching mode.
Now, the automatic switching is
based on the user interface
style of the view controller
that controls the status bar
appearance.
And as always, you can override
a specific preferred status bar
style on a view controller and
recurrent a particular style if
you desire.
Finally, it's not shown here but
just a quick note that we also
updated UIScroll view's
indicator style to behave in a
really similar way to this.
Next, let's talk about activity
indicators.
In iOS 13, these existing styles
are now deprecating.
And that's because they were
implying a very specific color
appearance, which doesn't really
make sense anymore.
But in their place, we've
introduced a handful of new
styles, which are just based on
the size of the activity
indicator.
They also use a nice dynamic
grey color by default, so they
look great in light and dark
mode without any changes.
But you can use the existing
color property to set a custom,
dynamic color, or even just a
static color like white, if you
want a particular fixed
appearance.
Next, here are a few things to
keep in mind when you're dealing
with text in your app.
Now, by default, text classes
like UILabel, UIText field, and
UIText view use the label color.
So, if you're just setting the
text on a new text field or text
view, or a label, you'll just
get a nice, correct appearance
in both light and dark by
default.
But if you use attributed
strings in your app, and you set
the attributed text of one of
these text classes, or if you
draw that attributed string
yourself manually, you should
keep in mind that you need to
specify a foreground color.
Drawing an attributed string
without any foreground color
attribute like this, is actually
defined to yield black text.
So, if you see black text in
your app in Dark Mode, and
you're using attributed strings,
just make sure you're specifying
a dynamic color like label, just
as you see here for that
foreground color attribute.
It's really quite easy.
Now, for those of you who have
embedded web content in your
app, you should know that Dark
Mode is opt in.
You can do this by using the
color scheme style property, or
a meta tag with the same name.
And then you can use the prefers
color scheme media query to
actually customize different
colors and images in both light
and dark mode.
You can learn more about all
these details in the Supporting
Dark Mode in Web Content video
from WWDC this year.
Now for those of you with tvOS
apps, there's a good chance that
you already support Dark Mode
since we've had that available
for a few years now.
Now, this year, your tvOS 13
apps will be expected to support
Dark Mode by default, just like
on iOS.
Most of the new API that we've
covered today, such as all the
dynamic colors and image assets,
it's all available.
But a few things like the new
system materials, are available
on iOS only.
Now, if you do already support
Dark Mode on your tvOS app, you
can feel free to adopt all of
these new features and new APIs
anywhere that you'd like.
But if your existing Dark Mode
implementation already is
working well, you don't need to
throw any of that away.
Now, if you'll be bringing your
iPad app to the Mac this year,
you can support Dark Mode on the
Mac in the exact same way, using
all the same API that we just
talked about for iOS.
Now, your Mac app will follow
the Dark Mode setting that the
user selects in system
preferences.
Very simple, just like on iOS.
But the only difference that you
actually will notice is that in
some cases, on the Mac, UIKit
will automatically provide
slightly different versions of
dynamic colors for those system
colors, and also some of the
materials, to better match the
ones that would normally be
provided by a framework like
AppKit on the Mac.
So, your app will look great
right alongside other AppKit
apps on the Mac as well.
Believe it or not, that's about
all you need to know so that you
can start updating all of your
apps for Dark Mode in iOS 13
today.
Once you build against the iOS
13 SCK, your app will
participate in Dark Mode by
default.
But you might have some work to
do, as you saw in our demos.
Now, we've made it really easy
to take advantage of all of
these new features and quickly
get your app going with Dark
Mode.
So be sure to start by using all
of the new dynamic system colors
and materials that we've made
available this year.
And then of course, create your
own custom appearances for
custom colors, custom images,
and more.
Finally, don't forget to take
advantage of all of the powerful
customizations and flexibility
built into UIKit to make your
apps really shine in Dark Mode.
We're really looking forward to
seeing how all of your apps look
in Dark Mode later this year.
For more information, we have
some more content available and
a little bit of sample code up
on our session page.
And with that, thank you very
much.
[ Applause ]