paint-brush
Building Dark Mode Theme in Android by@akshay-rana-gujjar
127 reads

Building Dark Mode Theme in Android

by Akshay RanaAugust 2nd, 2020
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Hello World, today we are going to see how we can implement a dark theme or night mode in our android application. This tutorial is going to be very simple and easy to understand. The dark theme is attractive to users and it is comfortable for low light conditions.

People Mentioned

Mention Thumbnail

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Building Dark Mode Theme in Android
Akshay Rana HackerNoon profile picture

Hello World, today we are going to see how we can implement a dark theme or night mode in our android application. This tutorial is going to be very simple and easy to understand. The dark theme is attractive to users and it is comfortable for low light conditions.

Recently many apps adapt dark mode in their app and the output of the night mode is amazing as many users love dark mode for their app. An example of a dark theme is Whatsapp dark mode in android see the below image.

Let's look at how our app will look like, see the below gif for our end result app.

Let's see how we can implement dark theme in our app.

Make layout for dark theme

First, we need to make our layout so that we can apply our dark theme to it.

If you see the above gif we used cardview to make our layout.

See the below code for layout.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:padding="10sp"
    >

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:cardCornerRadius="10sp"
        android:id="@+id/post"
        >
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="10sp"
            >
            <androidx.cardview.widget.CardView
                android:layout_width="70sp"
                android:layout_height="70sp"
                android:id="@+id/profilePicContainer"
                app:cardCornerRadius="100sp"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                >
                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"

                    android:src="@drawable/user1"
                    />
            </androidx.cardview.widget.CardView>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/username"
                android:text="John Doe"
                android:textAppearance="@style/TextAppearance.AppCompat.Large"
                app:layout_constraintLeft_toRightOf="@id/profilePicContainer"
                android:layout_marginStart="10sp"
                app:layout_constraintTop_toTopOf="@id/profilePicContainer"
                />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/time"
                android:text="Just now"
                android:textAppearance="@style/TextAppearance.AppCompat.Caption"
                app:layout_constraintLeft_toRightOf="@id/profilePicContainer"
                android:layout_marginStart="10sp"
                app:layout_constraintTop_toBottomOf="@id/username"
                />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="35sp"
                android:id="@+id/caption"
                android:text="Lorem Ipsum is simply dummy text of the printing and typesetting industry."
                app:layout_constraintTop_toBottomOf="@id/profilePicContainer"
                android:textAppearance="@style/TextAppearance.AppCompat.Body2"
                android:layout_marginTop="10sp"
                />

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="250sp"
                android:id="@+id/photoPost"
                android:scaleType="centerCrop"
                app:layout_constraintTop_toBottomOf="@id/caption"
                android:src="@drawable/post"
                android:layout_marginTop="10sp"
                />

            <ImageView
                android:layout_width="30sp"
                android:layout_height="30sp"
                android:id="@+id/likeBtn"
                android:src="@drawable/ic_like"
                app:layout_constraintLeft_toLeftOf="@id/photoPost"
                app:layout_constraintTop_toBottomOf="@id/photoPost"
                android:layout_marginTop="15sp"
                />

            <ImageView
                android:layout_width="30sp"
                android:layout_height="30sp"
                android:id="@+id/shareBtn"
                android:src="@drawable/ic_share"
                app:layout_constraintLeft_toRightOf="@id/likeBtn"
                app:layout_constraintTop_toBottomOf="@id/photoPost"
                app:layout_constraintTop_toTopOf="@id/likeBtn"
                android:layout_marginLeft="15sp"
                />


        </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.cardview.widget.CardView>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/changeThemeBtn"
        android:text="Change Theme"
        app:layout_constraintTop_toBottomOf="@id/post"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginTop="20sp"
        android:paddingHorizontal="10sp"

        />

</androidx.constraintlayout.widget.ConstraintLayout>

Now we need to set theme colors in the layout, for example, we need to set the background color of activity and cardview and also we need to set textview color and icon colors. But setting all the colors we need some way to set colors dynamically. 

We want to change the background color of activity to dark black color when we apply our dark theme in the application.

To make the dynamic values we will need to make attrs.xml file in the values folder. 

Make custom attribute values for layout.  

Create a new xml file in the values folder. Right-click on values folder and click on new then click values resource file and type attrs in the file name field.

Your values folder should look like below:

In the attrs.xml we will declare our custom attribute values like below.

<?xml version="1.0" encoding="utf-8"?>
<resources>
        <attr name="appWindowBackground" format="color" />
        <attr name="cardBackground" format="color" />
        <attr name="textColor" format="color"/>
        <attr name="textColorSecondary" format="color"/>
        <attr name="iconColor" format="color"/>
        <attr name="buttonBackground" format="color"/>
        <attr name="buttonTextColor" format="color"/>
</resources>

In the above code, we have defined 7 values and their type which is color. Each of the values, we will use in our layout file.

But before using these values we need to assign or set these values in our currently applied theme and also we will make our dark theme and update these attribute values.

See also: Cardview with Recyclerview Example

Make Dark theme in styles.xml and set attributes value.

First, we will set attribute values for our default or light theme then we will update those attribute values in the Dark theme. Let's do this.

<resources>
    <!-- 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>
        <item name="appWindowBackground">#CDDDDD</item>
        <item name="cardBackground">#FFFFFF</item>
        <item name="textColor">#000000</item>
        <item name="textColorSecondary">#717171</item>
        <item name="iconColor">#6A6A6A</item>
        <item name="buttonBackground">#CDCDCD</item>
        <item name="buttonTextColor">#000000</item>
    </style>

    <style name="DarkAppTheme" parent="Theme.AppCompat.Light.DarkActionBar">

        <item name="appWindowBackground">#393e46</item>
        <item name="cardBackground">#222831</item>
        <item name="textColor">#ffffff</item>
        <item name="textColorSecondary">#DAA8A8A8</item>
        <item name="iconColor">#00fff5</item>
        <item name="buttonBackground">@color/colorPrimary</item>
        <item name="buttonTextColor">#000000</item>
    </style>

</resources>

In the AppTheme we are setting our attribute value you are free to change as per your need. We are setting default colors. Then we made a new theme called DarkAppTheme and now this time we are setting all the custom attribute values to the dark theme matching colors.

We have set the app background color to black and other background colors to dark colors and set text and icon colors according to the dark theme.

Now the time to use these values in our layout. Open your activity XML file and check the background and textColor values as shown below.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:padding="10sp"
    android:background="?attr/appWindowBackground"
    >

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:cardCornerRadius="10sp"
        android:id="@+id/post"
        app:cardBackgroundColor="?attr/cardBackground"
        >
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="10sp"
            >
            <androidx.cardview.widget.CardView
                android:layout_width="70sp"
                android:layout_height="70sp"
                android:id="@+id/profilePicContainer"
                app:cardCornerRadius="100sp"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                >
                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"

                    android:src="@drawable/user1"
                    />
            </androidx.cardview.widget.CardView>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/username"
                android:text="John Doe"
                android:textAppearance="@style/TextAppearance.AppCompat.Large"
                app:layout_constraintLeft_toRightOf="@id/profilePicContainer"
                android:layout_marginStart="10sp"
                app:layout_constraintTop_toTopOf="@id/profilePicContainer"
                android:textColor="?attr/textColor"
                />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/time"
                android:text="Just now"
                android:textAppearance="@style/TextAppearance.AppCompat.Caption"
                app:layout_constraintLeft_toRightOf="@id/profilePicContainer"
                android:layout_marginStart="10sp"
                app:layout_constraintTop_toBottomOf="@id/username"
                android:textColor="?attr/textColorSecondary"
                />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="35sp"
                android:id="@+id/caption"
                android:text="Lorem Ipsum is simply dummy text of the printing and typesetting industry."
                app:layout_constraintTop_toBottomOf="@id/profilePicContainer"
                android:textAppearance="@style/TextAppearance.AppCompat.Body2"
                android:layout_marginTop="10sp"
                android:textColor="?attr/textColor"
                />

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="250sp"
                android:id="@+id/photoPost"
                android:scaleType="centerCrop"
                app:layout_constraintTop_toBottomOf="@id/caption"
                android:src="@drawable/post"
                android:layout_marginTop="10sp"
                />

            <ImageView
                android:layout_width="30sp"
                android:layout_height="30sp"
                android:id="@+id/likeBtn"
                android:src="@drawable/ic_like"
                app:layout_constraintLeft_toLeftOf="@id/photoPost"
                app:layout_constraintTop_toBottomOf="@id/photoPost"
                android:layout_marginTop="15sp"
                android:tint="?attr/iconColor"
                />

            <ImageView
                android:layout_width="30sp"
                android:layout_height="30sp"
                android:id="@+id/shareBtn"
                android:src="@drawable/ic_share"
                app:layout_constraintLeft_toRightOf="@id/likeBtn"
                app:layout_constraintTop_toBottomOf="@id/photoPost"
                app:layout_constraintTop_toTopOf="@id/likeBtn"
                android:layout_marginLeft="15sp"
                android:tint="?attr/iconColor"
                />


        </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.cardview.widget.CardView>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/changeThemeBtn"
        android:text="Change Theme"
        app:layout_constraintTop_toBottomOf="@id/post"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginTop="20sp"
        android:paddingHorizontal="10sp"
        android:textColor="?attr/buttonTextColor"
        android:background="?attr/buttonBackground"
        />
</androidx.constraintlayout.widget.ConstraintLayout>

If you noticed background and text color values, see how we use the attribute values in the activity layout so that these take values from the currently applied theme and set we set DarkAppTheme the values of the Dark theme will update and hence our layout values will also update and our dark theme will be in use. 

Let's see our we can switch our theme from the java code.

Set Theme to DarkAppTheme using Java

Now we have completed our XML part now its time to make logic to change the dark theme in the app. 

To apply the dark theme we need to call the setTheme method before setContentView function called in the onCreate function of the activity.
If you want to apply a dark theme on click of the button as shown in the above gif. We can use this code.

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) {
            setTheme(R.style.DarkAppTheme);
        }

        setContentView(R.layout.activity_main);

        Button changeThemeBtn = findViewById(R.id.changeThemeBtn);

        changeThemeBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) {
                    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
                } else {
                    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
                }

                finish();
                startActivity(new Intent(MainActivity.this, MainActivity.this.getClass()));
            }
        });

    }

To toggle the theme we need to check which theme is currently applied so that we can change the theme to do that we can use AppCompatDelegate class which helps us to determine which theme is currently applied by using its static function setDefaultNightMode.

AppCompatDelegate's setDefaultNightMode function will save the current theme configuration and we can check that value and apply our theme according to the check as we have shown in the above code. 

Now if you launch your app then when you click the button your nice looking dark theme is ready to rock the world.

Now if you want that if the user sets the theme and closes the app and relaunch the app and the last applied theme will be used then you have to use Shared Preferences to save the configuration and fetch the information on the launch of the app.

You can read about Shared Preferences here.

If you like this article do share it with your friends and batchmates.

Thanks for reading have a nice day.

Previously published at https://www.akshayrana.in/2020/07/how-to-make-dark-night-mode-theme-in.html