Richard
Richard

Reputation: 7443

How do I force apply a dark theme on Android?

According to the docs, I only need to set android:forceDarkAllowed=true in my activity manifest and inherit theme from parent="Theme.MaterialComponents.DayNight". I tried that, but it didn't work.

Here's my manifest file:

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity
        android:name=".MainActivity"
        android:forceDarkAllowed="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

And here's my styles.xml styles:

<style name="AppTheme" parent="Theme.MaterialComponents.Light">
    ...
</style>

<style name="AppTheme.Dark" parent="Theme.MaterialComponents.DayNight">
    ...
</style>

I tried to get the theme name of the activity by using this code below:

resources.getResourceName(
    packageManager.getPackageInfo(packageName, PackageManager.GET_META_DATA)
        .applicationInfo.theme
)

It shows me com.example.name:style/AppTheme and not AppTheme.Dark. How can I make it so that when I run the application, the MainActivity automatically sets itself to use AppTheme.Dark (i.e. dark mode) using android:forceDarkAllowed?

Upvotes: 11

Views: 30367

Answers (3)

Abandoned Cart
Abandoned Cart

Reputation: 4676

There are settings to allow dynamically setting day or night regardless of the current system setting.

Each of the options map directly to one of the AppCompat.DayNight modes:

Light - MODE_NIGHT_NO
Dark - MODE_NIGHT_YES
System default - MODE_NIGHT_FOLLOW_SYSTEM

To switch the theme, call AppCompatDelegate.setDefaultNightMode().

https://developer.android.com/guide/topics/ui/look-and-feel/darktheme#change-themes

This would apply to setting a DayNight theme. If you are trying to take advantage of the Force Dark in Android 10, it applies to the .Light sub-themes. It will not be applied to any of the DayNight or inherently dark themes.

Apps must opt-in to Force Dark by setting android:forceDarkAllowed="true" in the activity's theme. This attribute is set on all of the system and AndroidX provided light themes, such as Theme.Material.Light.

https://developer.android.com/guide/topics/ui/look-and-feel/darktheme#force-dark

Below that, the documentation also specifies how to exclude certain items, either in resources or code.

Force Dark can be controlled on specific views with the android:forceDarkAllowed layout attribute or with setForceDarkAllowed().

Beyond that, there are ways to detect the current system light / dark setting and respond to it using the options above, but that is for another post.

It's not a great solution for a dark theme and I apologize for any overlap with the accepted answer, but I do not agree with claiming something isn't possible because it isn't preferred.

Upvotes: 7

CommonsWare
CommonsWare

Reputation: 1007554

That is not how dark mode works on Android 10.

First, Android does not magically append .Dark to your theme at any point, regardless of whether or not the user enabled dark mode. You have android:theme="@style/AppTheme". So, Android will use AppTheme all the time, and your AppTheme.Dark will not be used.

Second, the idea behind DayNight is that you use that as you base theme all the time, and Android will switch between normal and dark modes based on user request. So, if you switch AppTheme to extend DayNight, and get rid of AppTheme.Dark, you will be matching what the documentation calls for.

android:forceDarkAllowed is for cases where you are not in position to use a DayNight theme, and you want Android to try to automatically convert your UI to a dark theme. If you wanted to keep AppTheme extending Light instead of DayNight, this might work (I personally have not tried it with a MaterialComponents theme). But, even then, it will only be when the user has enabled dark mode (e.g., tapped on the notification shade tile).

For example, in this sample app, I use DayNight for my theme:

<resources>

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

</resources>

I have different definitions for those colors in res/values/ and res/values-night/. I do not use forceDarkAllowed. And, when the user toggles night mode, my UI goes from:

DayNight normal

to:

DayNight dark mode

How can I make it so that when I run the application, the MainActivity automatically sets itself to use AppTheme.Dark (i.e. dark mode) using android:forceDarkAllowed?

You don't.

If you want a dark theme all the time, use a regular theme (not Light, not DayNight).

Upvotes: 18

Hadas
Hadas

Reputation: 986

  1. If your app uses a dark theme (such as Theme.Material), Force Dark will NOT be applied. Similarly, if your app's theme inherits from a DayNight theme, Force Dark will NOT be applied, due to the automatic theme switching.
  2. Dark theme is available in Android 10 (API level 29) and higher. Make sure that your device's API level is 29 + that your target SDK in the gradle is 29.
  3. There are two ways to apply dark theme:
    1. DayNight - custom-able theme - you control how dark/light theme will look like
    2. Force dark - you control the light theme, and if the user chooses dark mode the system will convert your views to dark theme at runtime.

Upvotes: 7

Related Questions