[MUSIC PLAYING]
CHRIS BANES: Hi.
Welcome to another episode in our series
on Material Design Components.
Following on from our episode on the basics of Material theming,
today we're going to develop on that and add a dark
them to an app.
So you might have heard about a dark theme
and wondering why you should add it to your app.
Well, we think there are a few reasons.
Firstly, dark themes can help reduce
eye strain for your users by matching the users'
ambient light conditions.
So during the night, your device will be dark.
And then during the day, it will be light.
Secondly, dark themes can help save power
in lots of popular devices.
So if your device has an OLED display--
and lots do these days--
each of those pixels you're seeing is individually lit.
Using a dark theme means that those pixels are lit
less, which ends up saving power overall,
which results in happy users.
Also, Android 10 adds a new system setting
which allows users to switch their device's theme.
As more apps support dark theme, apps which don't are
looking increasingly out of place on devices.
And finally, and perhaps the most important,
is that it's because your users want a dark theme.
Dark theme was consistently one of the most requested features
in Android for a very long time, and that means apps, too.
So that's the sales pitch over.
Now let's look at some code.
So the app we're going to be using today is called Reply,
and it's a Material study app, which is an email
and communication app.
So here you can see that we have two emulators running.
On the left, we have one that's running with the system dark
theme enabled, and on the right we
have one with just the light theme enabled.
So we'll quicker open Settings.
You'll see the two different themes in action.
Bit of a top tip for you.
If you can't use multiple devices,
there's also the dark theme quick setting
which you can add which allows you to easily flick
between the two themes.
So if we run the Material study app now,
you can see that the app has a light on both devices.
And that is because the version of Reply that we're using here
only has a light theme.
If we quickly run through the app, the main screen is a list.
It's an email inbox.
It's a [INAUDIBLE] list of emails.
And as you scroll, you can see the email list.
If we click on one, it opens up and expands
into the detailed screen.
At the bottom, we have the app bar.
You can see this bit here.
If we click on the fab, the Compose fab,
it opens up into the Compose screen.
And go back out that.
At the bottom, there's also, well, the actions.
You can open up a bottom navigation drawer,
and that contains the list of folders and labels.
So that's a quick run-through of the app.
Now, our task by the end of this video
is to add a dark theme to Reply.
Now, hopefully you caught our previous video
on the basics of Material theming
where Nick covered guidance around color, typography,
and shape.
Well, Material also has guidance on how to design a dark theme.
And that's also available on the material.io site.
Now, we're not going to cover all of the bits of guidance
on that page because there are quite a lot.
Instead, we're going to follow the design created
by Liam, who is one of the designers in the Material
advocacy team.
You can find his "Crafting a Dark Theme" video linked below
if you want to find out more of the theory behind the design.
The team also released that same design as a Figma prototype,
which you can see here.
So some of the key differences you can see
is that the primary color has changed.
So from a slightly darker orange,
it's gone to a lighter yellow.
You can see here.
But also the bottom app bar has changed color from a blue
to a gray.
Right, back to the code.
So we're going to be taking a look at two different ways
to implement a dark theme, and we're
going to start with something called Force Dark.
Force Dark is a feature added in Android 10
which allows you to very quickly implement
a dark theme in any app.
It works by the system analyzing each view in your app
and then automatically applying a dark theme
before it's drawn to the screen.
You can think of it as like a simplified color inversion.
It tries to work out what the background and foreground
colors are and then does a targeted inversion for text
colors and surface colors and that kind of stuff.
But what it does try and do is avoid photography
because you don't want those to be inverted.
To enable Force Dark in your app,
we just need to add one line to our theme.
So here we've got our themes.xml open,
and this is our theme, our Theme.Reply.
So here we're going to add a new item called
android:forceDarkAllowed and then set it to true.
Now, if we run it, and you can see that on our device
which has a dark theme, we're now
seeing a dark-themed version of Reply.
And you can see that it's actually
done a pretty good job.
It's converted all of the surface colors,
and the text colors are all nicely inverted, now light text
on dark.
But it's still kept the photography, so
all of these and the avatars, but also the iconography.
These icons, the illustrations, they've
been kept their original color, which is what you want.
It's kept the bottom app-bar color the same or at least very
close.
But one thing it has changed is the primary color.
So you can see that we've gone from this kind of mid yellow,
and it's drawn a very dark yellow.
If we bring the design up now on the left,
you can see that the primary color should actually
be a bit lighter in light theme, and the bottom app bar
should be going sort of dark surface color
rather than the blue that we currently have.
But I do think it's amazing that you can achieve this
just by setting one line in your theme.
I see this as a great way to rapidly release
a dark theme for devices running Android 10 and above.
But to fully achieve our design, which you see in the left
there, we're going to need to move
to the second method of implementing
a dark theme, which is by using Material Design Components's
theme system.
So back to our theme.
Before we began, we're going to remove
that forceDarkAllowed line because we're
no longer using that feature.
Material Components provides us with a special type
of theme called DayNight.
And that automatically changes its base theme
based on the system theme setting itself.
So our first step is to change our base theme.
So you can see here we extend from
Theme.MaterialComponents.Light, and we're
going to change it to DayNight instead.
So if we run that, we can see that very little has actually
changed here.
And that is because Reply's theme is quite extensive.
So you can see that it's setting a lot of the color
attributes available for material theming, which
is overriding all of that automatic behavior
from the DayNight theme itself.
To fix that, we're going to need to extract these color
attributes so that they're only used on the light theme.
Now, there's a couple of ways we can organize
our themes to support this.
I'm going to show you one way, but there are others.
So the first thing we're going to do
is change our theme to be called Base.Theme.Reply.
And then we're going to create a new theme called Theme.Reply,
and then make it extend the base theme.
Then we're going to move all of the kind
of light-theme-specific attributes
into that Theme.Reply.
So we'll just do that.
Cut those and paste them there.
There are some others.
So you probably want to set the statusBarColor as well.
That looks like it's been overwritten for light.
And then the rest should be probably OK.
So this will be used in our light theme.
Then we're going to need to create a new themes.xml,
this time in values-night.
And we're going to create--
we're going to copy that light theme over and then just remove
all these attributes in there.
So we made that theme also extend from Base.Theme.Reply.
And what that means is that the base theme here, it
contains all of the common stuff between the light
and the dark themes, which allows us to reuse everything,
which means that Theme.Reply only
contains the specific stuff for light or for the dark theme
itself.
Now, if we run, you can see that we now have a dark theme.
Now, this doesn't match the dark theme
that we want from our design, because this is now
going to be using the baseline dark theme from material,
but it's a step forward.
So my dark theme now has the values from the baseline theme.
Now we need to update it to be from our design.
So here I'm actually just going to fast-forward a little bit
and paste in the values.
So these are taken from the theme
from the design from Liam.
And they're nothing special.
They're just different values.
So instead of using in the light theme, in the primary,
we use the blue 700.
Just in the dark theme, we're using blue 200.
So for each of these, we're just using the appropriate color
for dark.
Now, if we run, you'll see that we're getting closer.
Like, the color primary is the right color now.
But the problem is that some things still aren't right.
So you can see that the bottom app bar, that should really
be using the dark surface rather than the primary color.
And also we now can no longer see the status bar color icons,
and that is because in the base theme
we're setting it to be light content.
So this one's actually pretty easy to fix.
MDC exposes an attribute called isLightTheme,
and so we can set this.
We can set this windowLightStatusBar
to match this.
And then it will be light when we're in a light theme
and then dark when we're in a dark theme.
So perfect.
So if we run that now quickly, you
can see that we can now actually see the status-bar content,
which is perfect.
So our final step is to fix this app-bar color.
So here we're using--
as you can see, we're using the primary color,
whereas really on the design, as you
can see on the left, what we want to use
is the surface color instead.
So the reason why the app is currently doing that
is because the style in the layout
is kind of using the BottomAppBar.Colored style.
Now, Colored means that it's going
to use the primary color as its background,
whereas what we want is to use the primary color in light
but then the surface color in dark.
Now, luckily, the Material Design Components team
has already thought about this and has
provided a special style called PrimarySurface which
does exactly what we want.
We can see that the app bar is now using the surface
color, which is perfect.
That's what we want.
The issue is that if you open the app bar now,
the content color of the items is wrong.
It's using dark text on a dark surface,
and obviously it's not very readable.
So the way this app is built is that it uses a color state list
for all of that content and this one here called
navigation_drawer_content.
And the reason why it's wrong is that it's
because it's using the colorOnPrimary attribute
for that content color, which will work in light
but it won't work in dark.
So again, we're going to switch that to use
colorOnPrimarySurface instead.
This is, again, brought by the MDC team
and will automatically switch to the right color
based on the theme.
So we run that now.
We can now say that the content color is correct.
So if you scroll up and down, we now have the right color.
And that's it for today's episode.
We saw how to implement a dark theme using both the Force
Dark functionality available for Android 10
as well as manually correcting a dark theme using the Material
Design Components styling system.
We've attached a link to the accompanying blog
post in the description of this video.
If you like this video, go ahead and like, share,
and subscribe to the Android Developers channel on YouTube,
and that's it.
Thanks for watching.
[MUSIC PLAYING]