Support both light and dark theme in Android Pie - android

Android Pie added the ability to toggle light/dark theme in the Settings -> Display -> Device Theme menu.
I want my app to apply the correct theme according to the Device Theme set in the device settings.
According to the Styles and Themes Android guide, for dark mode the app should use a theme that extends Theme.AppCompat, and for light mode the app should use a theme that extends Theme.AppCompat.Light.
So I created two themes in my app:
<style name="AppTheme.Dark" parent="Theme.AppCompat">
...
</style>
<style name="AppTheme.Light" parent="Theme.AppCompat.Light">
...
</style>
However in AndroidManifest.xml when I declare the application with the <application> tag I can only specify one theme in the android:theme attribute:
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="#style/AppTheme.Light"
tools:replace="android:name">
How do I declare my application in AndroidManifest.xml to dynamically pick #style/AppTheme.Light or #style/AppTheme.Dark according to the Device Theme set in the device settings?

If you want to change theme of an already existing activity, call recreate() after setTheme().
Note: don't call recreate if you change theme in onCreate(), to avoid infinite loop.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Call setTheme before creation of any(!) View.
setTheme(android.R.style.Theme_Dark);
// ...
setContentView(R.layout.main);
}

You may want to try Theme.AppCompat.DayNight instead of defining two themes. Its implementation in this video Cost of a Pixel Color.
However, when I test this on an emulator, toggling Settings -> Display -> Device Theme menu doesn't work. I have to toggle Developer Options -> Night Mode -> Always On and dark theme is picked automatically.
Since I don't own an Android Pie device, I'm not sure if this is a bug of emulator.

Related

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?
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:
to:
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).
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.
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.
There are two ways to apply dark theme:
DayNight - custom-able theme - you control how dark/light theme will look like
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.
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.

Dialog Theme.DeviceDefault forced

I am making a dialog, where I want to show EditTexts and Radio buttons.
But the theme is not applying. According to Layout Inspector, the Views have the correct theme applied (shown "forced"), but there is "android:style/Theme.DeviceDefault()", which is also "forced" (it is shown above my style, if that matters).
The problem is, that the Views look differently on different APIs, which I guess is caused by that DeviceDefault. I have not set anywhere anything about DeviceDefault, but it applies to all my Dialogs.
Any idea how to dissmiss it? Thanks.
Every API level has its own default theme and since you use the default theme to your app, android adjusts the theme depending on the API level which will be different on each device. Just remember that just the element of which you add the style attribute to gets the specified style attributes. The child objects or child view does not get the style attribute. If you want child views to inherit styles, instead apply the style with the android:theme attribute.
The problem is probolby linked to where, and how, you apply your own theme.
You should apply your theme in the AndroidManifest.xml file. If you apply your theme in the application tag or the activity tag, you cover different parts of the application with your theme. What you have done is hard to say without any code present.
You should apply your theme to one of the following sections of the file.
To cover the whole application
<manifest ... >
<application android:theme="#style/Theme.AppCompat" ... >
</application>
</manifest>
To cover just one activity
<manifest ... >
<application ... >
<activity android:theme="#style/Theme.AppCompat.Light" ... >
</activity>
</application>
</manifest>
If a view supports only some of the attributes that you declared in the style that you created, it then only applies those attributes and ignores the ones it does not support.
If you want to change the default style and colors, you can override them in the styles.xml file. Search for the item name that represents the color value and change corresponding value in the res/values/colors.xml file.
I hope this information will solv your problem, but as I said, it this really hard so exactly say without the code present.
About Theme.DeviceDefaul in Android:
There are many Themes available for Android devices.
Theme: the default for the earliest versions of Android up to 2.3 Gingerbread(10)
Theme.Holo: from Android 3.0 Honeycomb (11)
Theme.Material: from Android 5.0 Lollipop (21)
Theme.DeviceDefault: from Android 4.0 Ice Cream Sandwich (14), a theme that can be customized by the device manufacturer. It represents the native look of the device.
Specifying different themes:
Android's resource overlay system allows to specify styles based on device API level, via Android Studio will setup for you.
For example different versions of a style in res/values-v11 and res/values-v21.
/res/values/styles.xml is applied to every device and serves as base:
<resources>
<style name="AppTheme" parent="android:Theme.Light"/>
</resources>
/res/values-v11/styles.xml is loaded on all devices that have API level 11 and above (including those that are 21 and above):
<resources>
<style name="AppTheme" parent="android:Theme.Holo.Light"/>
</resources>
/res/values-v21/styles.xml is loaded on all devices that have API level 21 and above:
<resources>
<style name="AppTheme" parent="android:Theme.Material.Light"/>
</resources>
AndroidManifest.xml is the place where the custom theme is put to use.
<application
android:theme="#style/AppTheme"
...

Application theme dose't change using Theme in Editor in Android Studio

Hi I'm new to Android and I just want to change my App theme using "Theme in Editor" in Android Studio the Theme is to change preview but when I run application I don't see any conversion and when I want to edit Apptheme attribute of style it doesn't recognize for example Holo theme.
Go to AndroidManifest.xml.In Application Tag press CTR+ click on android:theme="#style/AppTheme" It open the style.xml then change your theme as you want in style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
Change android:theme="#style/AppTheme" to android:theme="#android:style/Theme.Holo" in your manifest file .

Set application theme globally in android

I am setting theme for each activity seperately in the corresponding activity.java file.
setTheme(android.R.style.Theme_Holo_Light);
Can i set the theme globally in the manifest file and then override it to change action bar background color etc.
In AndroidManifest.xml
<application
android:theme="#style/MyAppTheme">
In styles.xml
<style name="MyAppTheme" parent="#android:style/Theme.Holo.Light">
</style>
But it crashes.Why?
as per my guessing it is happening
cause your using theme which is not supporting to actionbar and your calling actionbar related code in such activity i mean your app may be crashing in that activity where you write actionbar related code but unfortunately the theme for that activity is not actionbar related theme thats why may be it comes
use actionbar related theme in that activity using
android:theme="#style/actionbar supported theme"
line in manifest against that activity

Android app theme - difference when using theme from style xml file

Why is there a difference between theme defined in AndroidManifest.xml and theme taken from styles.xml?
1) AndroidManifest.xml:
<application ... android:theme="#android:style/Theme.Black">
2) AndroidManifest.xml
<application ... android:theme="#style/AppTheme">
styles.xml
<resources>
<style name="AppTheme" parent="#android:style/Theme.Black" />
</resources>
1st setting gives black theme and no action bar. 2nd has dark action bar and light menu.
EDIT : options 1) and 2) - notice Menu and ActionBar
EDIT 2:
Why doesn't the 2nd option actually use the AppTheme (Theme.Black) ? (tested on SGS3)
You probably have another styles.xml file, perhaps under a directory like "values-v11", that is defining the #style/AppTheme differently than #android:style/Theme.Black and taking precedence over the file you're viewing/modifying.
#android:style/Theme.Black implements the exact theme implemented by Android (or device manufacturer). However, #style/AppTheme allows you to perform custom modification in your theme which actually extends the original Theme.Black from android, and in order to perform custom modifications, you use style resources.
In simple words, its just like using Activity class or YourOwnActivity class which extends Activity with extra features inside.
Styles.xml enables you to create your own themes. In AndroidManifest, you set the theme you want for an app or activity. You may want to use a system theme or your own. You can also extend other themes as you're doing setting "parent" attribute. For further information, check this out:
http://developer.android.com/guide/topics/ui/themes.html
You should try to put:
<resources>
<style name="AppTheme" parent="#android:style/Theme.Black" />
</resources>
in a xml file called res/themes.xml

Categories

Resources