Coders' Guidebook

How to toggle between day and night themes programmatically using Kotlin

In this tutorial, you will learn to apply the Material Components day and night themes to your Android app. We will also cover how to toggle between the themes while the app is running using Kotlin and personalise the colour palette of each theme.

day-night-theme-toggle.gif

Setting up the Material Components themes

The first thing you will need to do is check your app is correctly configured to support the Material Components themes. To do this, navigate through Project > Gradle Scripts and open both the Project and Module build.gradle files:

build-gradle.png

In the Project build.gradle file, check that the repositories section includes the reference to Google as shown below:

allprojects {
    repositories {
        google()
        jcenter()
    }
}

Next, in the Module build.gradle file, ensure the following implementation command is present in the dependencies section:

implementation 'com.google.android.material:material:1.1.0'

Version 1.1.0 must be used. If you need to make any changes then remember to resync the project when prompted by Android Studio.

resync-gradle.png

Once the Gradle files have been configured successfully your app should be ready to use the Material Components themes; however, if you still experience problems then it may be worth checking out Material Components' own Getting Started guide.

Creating the day and night theme files

We'll now create the files required to load (and modify) the day and night themes. When you create a new Android Studio project, it will generate for you a file called styles.xml. This styles file contains the details of the default theme and any custom styles that will be applied to the app's colour palette and components. Open the styles.xml by navigating through Project > app > res > values. In the styles file, you may find an entry that looks something like this:

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>

The opening style tag has the name attribute 'AppTheme'. This means it is the default theme for the app. Any items added to this style entry will apply regardless of whether the day or night theme is active. For this reason, you may want to delete the item entries which refer to specific colours (colorPrimary, colorPrimaryDark etc.) unless you want those colours to apply to both the day and the night themes. The parent attribute of the opening style tag specifies which theme the AppTheme style will inherit its default colour and styling instructions from. We want to use a customised Material Components day/night theme as the parent so change the parent attribute to something like "Theme.name of your app". For example, if your app was called "Recipes" then you may want to write the parent attribute like this:

<style name="AppTheme" parent="Theme.Recipes">

Don't worry if the parent attribute causes an error. This is simply because we have not yet created the theme. We'll fix that in just a moment. Before we do though, it's worth mentioning again that any style instructions in the styles.xml file will apply regardless of whether the day or the night theme is active. For this reason, it may be worth deleting entries like the following if you see them in the styles.xml file:

<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
				
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />

Those two style entries apply a default Android theme to the action bar and would override the day and night themes. If you want the day and night themes to apply to the action bar as well then you should delete the two style entries listed above, as well as any other auto-generated style entries that interfere with the day and night themes.

Moving on, let's now create the file that will manage the day theme. Right-click the values folder and select New > Values Resource File. Name the file themes then press OK.

new-themes.png

A file called themes.xml will open in the editor and it should contain opening and closing resource tags. The details of the day theme will go between the tags like this:

<resources>
   <style name="Theme.Notes" parent="Theme.MaterialComponents.DayNight">
       <item name="colorPrimary">@color/colorPrimary</item>
       <item name="colorPrimaryDark">@color/colorSecondary</item>
       <item name="colorSecondary">@color/colorSecondary</item>
   </style>
</resources>

The style tags are essential and should be written as above; however, the items are optional. The parent attribute of the opening style tag imports the information from the Material Components DayNight theme. You can learn more about this theme here. It uses a readymade set of colours detailed below (1 - Day mode; 2 - Night mode):

material-components-theme-colours.png

Any style entries and items declared in this themes.xml file will apply to the day theme only. In the example code above, we overwrite the dark, primary dark and secondary colours of the Material Components day theme. You can learn more about how to personalise the colours used in a theme at the end of this tutorial.

Moving on, let's create the themes file which will manage the night theme. Similar to before, right-click the values folder and select New > Values Resource File. Name the file themes and set the directory to values-night then press OK.

new-themes-night.png

Another file called themes.xml will open in the editor. It will work in much the same way as the previous themes.xml file but with one key difference: the parent attribute of the style element should be "Theme.MaterialComponents".

<resources>
   <style name="Theme.Notes" parent="Theme.MaterialComponents">
   </style>
</resources>

Any colours or style items that are to be applied to the night theme only should go between those style tags.

Switching between the day and night themes programmatically

In this section, we will discuss how the user can toggle between the day and night themes. This will be achieved programmatically using Kotlin. We'll be using a switch object to toggle between the themes; however, you could apply these principles to other objects/widgets such as buttons and radio buttons. Open the layout of your choosing (e.g. activity_main.xml or a dedicated settings page layout file) then drag and drop a switch object from the palette onto the layout interface.

switch-object.png

Select the switch object then refer to the Attributes panel. Assign the object a memorable ID such as 'themeSwitch'.

theme-switch.png

Next, open the Kotlin file which manages the layout. The MainActivity.kt file may be suitable here, although you may have a dedicated Settings page Kotlin file too. Copy and paste the following code inside the onCreate function:

themeSwitch.setOnCheckedChangeListener { _, checkedId ->
    when (checkedId) {
        true -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)

        false -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
    }
}

The above code uses the 'setOnCheckedChangeListener' command to check the status of the switch with the ID themeSwitch. When the switch is turned on the checkedId value is set to true. In which instance, the AppCompatDelegate command activates night mode and the MaterialComponents night theme. Likewise, when the switch is turned off, night mode is deactivated and the day theme is used instead.

day-night-theme-toggle.gif

And just like that, the user can now toggle between the day and night themes using the switch. Other activities in the app will also adopt the new theme; however, they may not remember the theme selection if the app is restarted. To achieve this, then you would need to save the user's selection in the app using the shared preferences file or something similar.

Customising the colours of a theme

The default colours used in the MaterialComponents themes are shown below (1 - Day; 2 - Night):

material-components-theme-colours.png

When designing your app, you may wish to customise the colour palette and override aspects of the MaterialComponents themes. For example, you may like to change the secondary colour of the night theme from #03DAC6 to #84C9FB (if you are looking for colour codes then you may like to use our colour picker). To add custom colours to your app, navigate through Project > app > res > values and open the colors.xml file.

colors-file.png

Android Studio will likely have already generated some colours in the file. You can similarly add your custom colours. Insert opening and closing color tags, assign the opening color tag a name, and input the colour code between the tags. For example, we could add the #84C9FB colour by typing the following:

<color name="nightColorSecondary">#84C9FB</color>

That colour can now be used elsewhere in the app by calling its name 'nightColorSecondary'. If you want to apply the colour to both the day and the night themes, then open the styles.xml file. Otherwise, open the themes.xml for the specific theme you wish to modify.

To override a colour used in a theme, you need to insert a set of item tags between the two style tags for that theme. The opening item tag should have a name attribute that begins 'color' followed by the colour you are overriding. For example, if you wished to override the onSecondary colour of the theme then your item tags would read <item name="colorOnSecondary"></item>. The name of the colour you would like to use (as specified in the colors.xml file) then goes between the item tags in the format @color/name-of-colour. Putting this all together, you could set the secondary colour of the day and/or the night theme to #84C9FB in the following ways:

Overwrite the secondary colour of both the day and the night themes using the styles.xml file.

<style name="AppTheme" parent="Theme.name-of-app">
    <item name="colorSecondary">@color/colorSecondary</item>
</style>

Overwrite the secondary colour of the day theme only using its themes.xml file.

<style name="Theme.name-of-app" parent="Theme.MaterialComponents.DayNight">
    <item name="colorSecondary">@color/colorSecondary</item>
</style>

Overwrite the secondary colour of the night theme only using its themes.xml file.

<style name="Theme.name-of-app" parent="Theme.MaterialComponents">
    <item name="colorSecondary">@color/colorSecondary</item>
</style>

And that's it. You can now programmatically toggle between day and night themes and customise the colour palette those themes use. If you would like to learn more about designing custom themes and styling individual app components (such as buttons etc.) then you may like to check out our guide on how to build a 'notes' app from scratch.

<<< Previous

Next >>>